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

# Sweep a cut over a run's answers

> Tunes one cut of a bands aggregation without asking an engine anything: re-decides the runs' labeled items from the answers and attribute values they hold at every point where moving the cut changes an outcome, and judges each point by the decision's objective, as loss_report does. Name the aggregation (as `near_cuts` gives it, or `aggregations.<name>`) and the cut by its current `at`; without `at`, each of its cuts is swept alone with the others where they are. The cut moves only between its neighbours. Each cut lists the loss per case over its ranges (`points`), each kept inside the input's range, the `best` range with what it fixes and breaks against the current cut, and `cross_validation`: the best cut chosen again without each fold of item groups (5 folds, stratified by label; fewer with fewer groups) and scored on that fold; null with fewer than 2 item groups on either side of the cut (cases the band below gets right, cases the band above gets right). `holds: false` means the in-sample best may be noise: keep the cut unless a run of the moved cut is accepted by loss_report. Runs are named by `run_ids` from evaluate with `items` or `cases`, one structure; items are left out as loss_report leaves them out. Spends nothing. An unknown or expired run is 404 RUN_UNKNOWN; an aggregation that isn't bands or isn't on the result's path is 400 AGGREGATION_INVALID; a cut it doesn't have is 400 CUT_UNKNOWN; a result that is a value is 400 OUTCOMES_INVALID; a sweep that would take too long (many items over a large structure) is 422 REQUEST_TOO_LARGE: send fewer runs, or name one cut.



## OpenAPI

````yaml /openapi.json post /v1/decisions/{decision_id}/cut-sweeps
openapi: 3.1.0
info:
  title: Moonbounce Decisions API
  version: 0.0.0
  description: >-
    Moonbounce decisions: evaluate an item's state against a decision structure
    (System One questions, attributes you supply and aggregations over both),
    record feedback and import labeled examples, review a ranked queue, and
    improve the structure through suggestions that ship as code diffs, each with
    a preview (backtest) and an evidence label.


    **Authentication.** Send an API key as `Authorization: Bearer <key>` on
    every operation except `GET /health` and `POST /v1/structures/hash`. Call
    the API from a server, never a browser: a key must not reach one, and the
    API sends no CORS headers. A key belongs to one organization and one
    environment: production, or test for a key with the `env:test` permission.
    Test traffic never counts as production traffic.


    **Requests.** JSON bodies (`Content-Type: application/json`) of at most 1
    MB, parsed strictly: duplicate keys, lone surrogates, integers outside
    ±(2^53 - 1), `__proto__` keys, U+0000 and nesting deeper than 64 are a 400.


    **Retries.** Send an `Idempotency-Key` on every POST under /v1 that takes
    one (all but `POST /v1/structures/hash` and `POST /v1/review/items/fill`,
    whose retry is another fill within the day's budget). Keep it for the
    request's retries. The same key with the same request returns the first
    stored result, marked `Idempotent-Replayed: true`, for 24 hours (410 if that
    result was since deleted); with another request it is 422
    IDEMPOTENCY_KEY_REUSED. Keys are scoped to the organization and environment
    across every operation, so use a fresh key per request. A request that
    failed before its result was stored runs again when retried. 429 and 503
    under /v1 may carry `Retry-After` (seconds); a daily QUOTA_EXCEEDED cap
    instead names its reset time.


    **Errors.** Every error under /v1 is `{"error": {"type", "message",
    "reason"?, "param"?, "details"?}}` (ErrorBody); `GET /health` answers its
    own shape. Every response carries a `Request-Id` header. Rate limits apply
    per key, and per client IP for requests without a valid key; a 429
    RATE_LIMITED carries `Retry-After`.
servers:
  - url: https://api.moonbounce.ai
    description: Production
security: []
paths:
  /v1/decisions/{decision_id}/cut-sweeps:
    post:
      tags:
        - objective
      summary: Sweep a cut over a run's answers
      description: >-
        Tunes one cut of a bands aggregation without asking an engine anything:
        re-decides the runs' labeled items from the answers and attribute values
        they hold at every point where moving the cut changes an outcome, and
        judges each point by the decision's objective, as loss_report does. Name
        the aggregation (as `near_cuts` gives it, or `aggregations.<name>`) and
        the cut by its current `at`; without `at`, each of its cuts is swept
        alone with the others where they are. The cut moves only between its
        neighbours. Each cut lists the loss per case over its ranges (`points`),
        each kept inside the input's range, the `best` range with what it fixes
        and breaks against the current cut, and `cross_validation`: the best cut
        chosen again without each fold of item groups (5 folds, stratified by
        label; fewer with fewer groups) and scored on that fold; null with fewer
        than 2 item groups on either side of the cut (cases the band below gets
        right, cases the band above gets right). `holds: false` means the
        in-sample best may be noise: keep the cut unless a run of the moved cut
        is accepted by loss_report. Runs are named by `run_ids` from evaluate
        with `items` or `cases`, one structure; items are left out as
        loss_report leaves them out. Spends nothing. An unknown or expired run
        is 404 RUN_UNKNOWN; an aggregation that isn't bands or isn't on the
        result's path is 400 AGGREGATION_INVALID; a cut it doesn't have is 400
        CUT_UNKNOWN; a result that is a value is 400 OUTCOMES_INVALID; a sweep
        that would take too long (many items over a large structure) is 422
        REQUEST_TOO_LARGE: send fewer runs, or name one cut.
      operationId: sweepCut
      parameters:
        - schema:
            $ref: '#/components/schemas/DecisionId'
          required: true
          name: decision_id
          in: path
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CutSweepRequest'
      responses:
        '200':
          description: The sweep
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CutSweepResponse'
        '400':
          description: 'Invalid request: `param` names the field at fault when one applies'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '401':
          description: Missing or invalid API key (reason KEY_INVALID)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '403':
          description: The key may not do this
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: Not found, or not in this key's organization and environment
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: >-
            The request is well formed but cannot be processed
            (IDEMPOTENCY_KEY_REUSED requires a fresh key; REQUEST_TOO_LARGE
            requires a smaller request)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '429':
          description: >-
            RATE_LIMITED: retry after Retry-After seconds; QUOTA_EXCEEDED:
            details.reset_at gives the daily reset time (no Retry-After)
          headers:
            Retry-After:
              schema:
                type: string
                description: Seconds to wait before retrying, when waiting helps.
              required: false
              description: Seconds to wait before retrying, when waiting helps.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: >-
            Temporarily unavailable, with Retry-After (for example reason
            AUTH_UNAVAILABLE, ENGINE_UNAVAILABLE or STORE_UNAVAILABLE): retry
            with the same Idempotency-Key
          headers:
            Retry-After:
              schema:
                type: string
                description: Seconds to wait before retrying, when waiting helps.
              required: true
              description: Seconds to wait before retrying, when waiting helps.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      security:
        - bearerAuth:
            - decisions:develop
components:
  schemas:
    DecisionId:
      type: string
      pattern: ^[a-z][a-z0-9_.-]{0,127}$
    CutSweepRequest:
      type: object
      properties:
        run_ids:
          type: array
          items:
            $ref: '#/components/schemas/EvrId'
          minItems: 1
          maxItems: 50
          description: >-
            Runs of one structure, from evaluate with `items` or `cases`, as a
            loss_report side takes them.
        aggregation:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            The bands aggregation whose cut to sweep: its name, as `near_cuts`
            gives it, or its path (`aggregations.<name>`).
        at:
          type: number
          description: >-
            The cut to sweep, by its current `at`. Without it, every cut of the
            aggregation, one at a time.
      required:
        - run_ids
        - aggregation
      additionalProperties: false
    CutSweepResponse:
      type: object
      properties:
        environment:
          $ref: '#/components/schemas/Environment'
        decision_id:
          $ref: '#/components/schemas/DecisionIdOutput'
        structure_hash:
          $ref: '#/components/schemas/StructureHashOutput'
        aggregation:
          type: string
          pattern: ^[a-z][a-z0-9_]{0,63}$
          description: The bands aggregation swept.
        objective:
          type: object
          properties:
            source:
              type: string
              enum:
                - stored
                - balanced
              description: >-
                `stored`: the decision's stored objective. `balanced`: none is
                set, so each outcome's mistakes weigh the same in total.
            revision:
              type:
                - integer
                - 'null'
              minimum: 1
            objective_hash:
              type:
                - string
                - 'null'
              description: The stored objective as written (null when balanced).
            effective_hash:
              type: string
              description: >-
                The hash of the severities and target scored by (each run weighs
                outcomes by its own cases). Never compare reports under
                different ones.
            unknown_outcomes:
              type: array
              items:
                type: string
          required:
            - source
            - revision
            - objective_hash
            - effective_hash
            - unknown_outcomes
          additionalProperties: true
          description: What this run scored with.
          x-moonbounce-sdk-known-fields: true
        'n':
          type: integer
          minimum: 0
          description: Cases scored, as loss_report counts them.
        excluded:
          type: object
          properties:
            unlabeled:
              type: integer
              minimum: 0
            failed_transient:
              type: integer
              minimum: 0
            outcome_not_in_result:
              type: integer
              minimum: 0
          required:
            - unlabeled
            - failed_transient
            - outcome_not_in_result
          additionalProperties: true
          description: Items left out, as loss_report leaves them out.
          x-moonbounce-sdk-known-fields: true
        cuts:
          type: array
          items:
            $ref: '#/components/schemas/CutSweep'
          description: One per cut swept, in the aggregation's order; each moves alone.
      required:
        - environment
        - decision_id
        - structure_hash
        - aggregation
        - objective
        - 'n'
        - excluded
        - cuts
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
    ErrorBody:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              $ref: '#/components/schemas/ErrorType'
            reason:
              type: string
              pattern: ^[A-Z][A-Z0-9_]+$
              description: >-
                Set where a caller can act on it, one of the reasons in the
                ErrorReason schema. New reasons may be added: treat an unknown
                one by the status and `type`.
            message:
              type: string
              description: For people; don't parse it.
            param:
              type: string
              description: >-
                The request field at fault, as a dotted path
                (`attribute_values.region`, `claims.1.value`).
            details:
              type: object
              properties:
                issues:
                  type: array
                  items:
                    $ref: '#/components/schemas/ErrorIssue'
              additionalProperties: {}
          required:
            - type
            - message
          additionalProperties: true
          x-moonbounce-sdk-known-fields: true
      required:
        - error
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
    EvrId:
      type: string
      pattern: >-
        ^evr_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    Environment:
      type: string
      enum:
        - production
        - test
      description: >-
        The environment of the key that made the call: `production` or `test`.
        Evaluations, feedback, reviews and suggestions are separate per
        environment; registered structures are shared.
    DecisionIdOutput:
      type: string
      pattern: ^[a-z][a-z0-9_.-]{0,127}$
    StructureHashOutput:
      type: string
      pattern: ^sha256:[0-9a-f]{64}$
    CutSweep:
      type: object
      properties:
        at:
          type: number
          description: The cut's current value.
        outcome:
          type: string
          minLength: 1
          maxLength: 200
          description: The outcome at and above the cut.
        below:
          type: string
          minLength: 1
          maxLength: 200
          description: The outcome just below it.
        bounds:
          type: object
          properties:
            above:
              type:
                - number
                - 'null'
            below:
              type:
                - number
                - 'null'
          required:
            - above
            - below
          additionalProperties: true
          description: >-
            The cut moves strictly between its neighbours: `above` the cut
            beneath it, `below` the cut over it. Null: none.
          x-moonbounce-sdk-known-fields: true
        moving:
          type: integer
          minimum: 0
          description: >-
            Cases whose outcome this cut can change: a known value between its
            neighbours, at which the two bands give different outcomes. The rest
            keep theirs at every point.
        current:
          type: object
          properties:
            loss_per_case:
              type: number
              minimum: 0
          required:
            - loss_per_case
          additionalProperties: true
          x-moonbounce-sdk-known-fields: true
        points:
          type: array
          items:
            type: object
            properties:
              at:
                type: number
                description: >-
                  A cut in the range: the current cut when the range holds it,
                  else the middle; an open-ended range is given the width of its
                  neighbour.
              from:
                type:
                  - number
                  - 'null'
                description: >-
                  Every cut above this value and up to `to` gives the same loss
                  (neighbouring ranges with equal loss are merged, so an outcome
                  may change inside one). Null: no lower bound.
              to:
                type:
                  - number
                  - 'null'
                description: 'Null: no upper bound.'
              loss_per_case:
                type: number
                minimum: 0
              fixed:
                type: integer
                minimum: 0
                description: Cases wrong at the current cut that this cut gets right.
              broken:
                type: integer
                minimum: 0
                description: Cases right at the current cut that this cut gets wrong.
            required:
              - at
              - from
              - to
              - loss_per_case
              - fixed
              - broken
            additionalProperties: true
            x-moonbounce-sdk-known-fields: true
          description: >-
            One per range of cuts that gives a different loss, ascending. A
            response lists at most 100, nearest the current cut.
        points_total:
          type: integer
          minimum: 0
        best:
          type: object
          properties:
            at:
              type: number
              description: >-
                A cut in the range: the current cut when the range holds it,
                else the middle; an open-ended range is given the width of its
                neighbour.
            from:
              type:
                - number
                - 'null'
              description: >-
                Every cut above this value and up to `to` gives the same loss
                (neighbouring ranges with equal loss are merged, so an outcome
                may change inside one). Null: no lower bound.
            to:
              type:
                - number
                - 'null'
              description: 'Null: no upper bound.'
            loss_per_case:
              type: number
              minimum: 0
            fixed:
              type: integer
              minimum: 0
              description: Cases wrong at the current cut that this cut gets right.
            broken:
              type: integer
              minimum: 0
              description: Cases right at the current cut that this cut gets wrong.
            change:
              type: number
              description: >-
                Loss per case at the best point minus at the current cut:
                negative is better.
            fixed_examples:
              type: array
              items:
                type: string
              description: >-
                A few of its cases, costliest first, by the id each case
                carries.
            broken_examples:
              type: array
              items:
                type: string
              description: >-
                A few of its cases, costliest first, by the id each case
                carries.
          required:
            - at
            - from
            - to
            - loss_per_case
            - fixed
            - broken
            - change
            - fixed_examples
            - broken_examples
          additionalProperties: true
          description: >-
            The lowest loss; among equals, the range holding the current cut,
            else the one nearest it. In-sample: `cross_validation` says whether
            it generalizes.
          x-moonbounce-sdk-known-fields: true
        cross_validation:
          anyOf:
            - type: object
              properties:
                folds:
                  type: integer
                  minimum: 0
                  description: >-
                    5, or fewer with fewer item groups (then one group per fold:
                    leave one group out).
                groups:
                  type: integer
                  minimum: 0
                  description: >-
                    Item groups the folds are made of, each kept in one fold:
                    stored cases grouped by content as list_cases groups them,
                    other items (a dry run's) by identical answers, attribute
                    values and label.
                current_loss_per_case:
                  type: number
                  minimum: 0
                tuned_loss_per_case:
                  type: number
                  minimum: 0
                  description: >-
                    Each case's loss at the best cut chosen without its fold,
                    averaged over every case.
                fold_cuts:
                  type: array
                  items:
                    type: number
                  description: The best cut each fold's training cases chose, by fold.
                holds:
                  type: boolean
                  description: >-
                    Tuning beats the current cut on cases it did not see:
                    `tuned_loss_per_case` is lower. False: the in-sample best
                    may be noise.
              required:
                - folds
                - groups
                - current_loss_per_case
                - tuned_loss_per_case
                - fold_cuts
                - holds
              additionalProperties: true
              x-moonbounce-sdk-known-fields: true
            - type: 'null'
          description: >-
            Cross-validation of choosing the cut by the lowest loss: folds over
            item groups, stratified by label. Null when, among the cases the cut
            can move, fewer than 2 item groups are ones the band below gets
            right, or fewer than 2 the band above gets right: too little
            evidence on a side to check what moving the cut costs there.
      required:
        - at
        - outcome
        - below
        - bounds
        - moving
        - current
        - points
        - points_total
        - best
        - cross_validation
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
    ErrorType:
      type: string
      enum:
        - invalid_request
        - authentication
        - permission_denied
        - not_found
        - conflict
        - rate_limited
        - engine_failed
        - unavailable
        - internal
    ErrorIssue:
      type: object
      properties:
        param:
          type: string
        code:
          type: string
          pattern: ^[A-Z][A-Z0-9_]+$
          description: >-
            Stable, extensible issue code; unknown codes still have a parameter
            and human-readable message.
        message:
          type: string
      required:
        - param
        - code
        - message
      additionalProperties: true
      x-moonbounce-sdk-known-fields: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key, sent as `Authorization: Bearer <key>`. Each operation lists
        the scope its key needs: `decisions:evaluate` (evaluate and read
        evaluations), `decisions:feedback` (your app's feedback) or
        `decisions:develop` (everything else, including owner feedback and the
        review queue). An operation listing no scope takes any scoped key. A key
        with no scope, or without the operation's, gets 403 INSUFFICIENT_SCOPE.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.