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

# Answer one round of proposed refinements

> Records what a person decided about one round and writes what they allowed. The consent unit is the ROUND — the whole proposed diff, with per-item marks inside it — because one ask per item at volume is reflex approval and makes the gate decorative.

The marks name items by INDEX, into the item list exactly as the round sent it. The engine ordered those items, so a client that reordered them would post somebody's approval onto a different edit with a straight face — `answerQuestion`'s own indexing rule, for the same reason. `accept-round` carries no marks at all: saying "all of it" must not require enumerating the round back.

A rejection writes no refinement, and the message a person types is not decoration: it reaches the next review as a correction, so the same fact is not proposed again tomorrow night.



## OpenAPI

````yaml /en/openapi/v3-current/narya.yaml post /v1/refinements/rounds/{roundId}/answer
openapi: 3.1.0
info:
  title: Narya Host API
  version: 1.0.0
  description: >-
    The contract between the Narya host and every client. One long-lived host
    serves this API over a Unix socket in your Narya home. The terminal client
    and the one-shot command that Lerian ships drive this API, and a client you
    write drives the same one.


    Requests authenticate with a bearer token issued by the identity provider
    the host is configured with. An operation that declares another security
    scheme also accepts that credential. A request without a valid credential
    gets 401 with NRY-0011. A caller whose role lacks the permission an
    operation needs gets 403 with NRY-0028.


    Submitting a message returns 202 with a turn id. Everything the turn
    produces streams over GET /v1/events as server-sent events with a typed
    envelope, and a stream resumes from a Last-Event-ID header.


    One error envelope: code, title and message. Codes are NRY- followed by four
    digits. Cursors are opaque.
servers: []
security:
  - bearerAuth: []
tags:
  - name: host
    description: The host process itself — version, uptime, mode, store.
  - name: sessions
    description: Durable conversation containers. Archive, never destroy.
  - name: messages
    description: Submitting work into a session and interrupting it.
  - name: events
    description: The server-sent event stream every client consumes.
  - name: lanes
    description: Parallel tracks inside a session — main, subagent, side.
  - name: agents
    description: Named recipes — instructions, tools, model, policy. Read-only in v1.
  - name: ladder
    description: >-
      What a person can type: the skills and command files in force for one
      repository, and expanding one into text. Five origins merged, nearest
      winning a name, the repository's own rungs gated on trust.
  - name: permissions
    description: Pending permission asks, decisions, and the decision audit.
  - name: intercom
    description: Sessions on one machine finding and messaging each other.
  - name: packages
    description: The one thing a user installs — resources, Go code, or both.
  - name: extensions
    description: >-
      Host-side extensions and the operations each exposes over the wire. This
      is the generic lane a host extension uses to serve its own client half (a
      TUI component, a web panel) or any API-only consumer, without adding
      routes to this contract.
  - name: workflows
    description: Deterministic multi-agent orchestration runs.
  - name: providers
    description: Model suppliers, their auth state, and the model catalogue.
  - name: monitors
    description: >-
      Long-running watchers a session keeps beside its conversation — a test
      runner in watch mode, a build, a log being followed. Started by the model
      or by the person, always listed, always killable.
  - name: records
    description: The queryable local record of everything that happened.
  - name: environments
    description: >-
      Where a session's code lives and its commands run — this machine, or a
      container narya operates. A session that names none runs here.
  - name: schedules
    description: >-
      Work the host's own clock starts with nobody present — a repository, a
      prompt, a rule and what one fire may spend. Cancel, never destroy.
  - name: sharing
    description: >-
      Publishing a session from a developer's own home to the organisation's,
      and what is held back before a byte leaves the machine.
  - name: refinements
    description: >-
      What this owner has taught narya and allowed it to keep — distilled facts,
      and the skills, agents and commands the model wrote for itself. Propose,
      read, consent, roll back. Nothing here fires until a person answers.
  - name: platform
    description: >-
      Calls Lerian's control plane made to a home it hosts, as this home
      recorded them.
paths:
  /v1/refinements/rounds/{roundId}/answer:
    parameters:
      - $ref: '#/components/parameters/RoundIdParam'
    post:
      tags:
        - refinements
      summary: Answer one round of proposed refinements
      description: >-
        Records what a person decided about one round and writes what they
        allowed. The consent unit is the ROUND — the whole proposed diff, with
        per-item marks inside it — because one ask per item at volume is reflex
        approval and makes the gate decorative.


        The marks name items by INDEX, into the item list exactly as the round
        sent it. The engine ordered those items, so a client that reordered them
        would post somebody's approval onto a different edit with a straight
        face — `answerQuestion`'s own indexing rule, for the same reason.
        `accept-round` carries no marks at all: saying "all of it" must not
        require enumerating the round back.


        A rejection writes no refinement, and the message a person types is not
        decoration: it reaches the next review as a correction, so the same fact
        is not proposed again tomorrow night.
      operationId: answerRefinementRound
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefinementRoundAnswer'
      responses:
        '200':
          description: >-
            Answered, with what the answer left behind: the rows written, and
            every accepted mark this host would not write, by name.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefinementRoundOutcome'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '413':
          $ref: '#/components/responses/RequestBodyTooLarge'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    RoundIdParam:
      name: roundId
      in: path
      required: true
      description: >-
        The refinement round's id, as proposeRefinement returned it or as
        refinement-proposed announced it.
      schema:
        type: string
        format: uuid
  schemas:
    RefinementRoundAnswer:
      type: object
      description: >-
        What a person decided about one round. Three verbs and four answers on
        the screen: accepting the round, accepting the marked items, rejecting
        the round, and rejecting it with a message — the last two write exactly
        the same rows (none) and differ only in what the next review reads.
      required:
        - roundAnswer
      properties:
        roundAnswer:
          type: string
          enum:
            - accept-round
            - accept-marked
            - reject-round
          x-enum-varnames:
            - RefinementRoundAnswerAcceptRound
            - RefinementRoundAnswerAcceptMarked
            - RefinementRoundAnswerRejectRound
        marks:
          type: array
          description: >-
            One entry per item a person marked, naming it by the index the round
            sent. Refused alongside `accept-round`, which means all of it and
            carries no marks on purpose: a client saying "all of it" must not
            have to enumerate the round back.
          items:
            $ref: '#/components/schemas/RefinementMark'
        message:
          type: string
          description: >-
            What the person typed. It is not decoration: the next review reads
            it as a correction, which is what stops the same rejected fact being
            proposed again tomorrow night.
          maxLength: 4000
      examples:
        - roundAnswer: accept-marked
          marks:
            - index: 0
              accepted: true
            - index: 1
              accepted: false
          message: the second one is about my editor, not about this repository
    RefinementRoundOutcome:
      type: object
      description: What one answered round left behind.
      required:
        - written
        - refused
      properties:
        written:
          type: array
          description: One row per accepted mark that survived, in the round's own order.
          items:
            $ref: '#/components/schemas/Refinement'
        refused:
          type: array
          items:
            $ref: '#/components/schemas/RefinementRefusal'
        appliedToSessionId:
          type: string
          format: uuid
          description: >-
            The ONE conversation that takes this round on its next turn — the
            one the round was taught in, which has already paid for the prompt
            prefix this changes. Every other session, including another window
            of the same person's, takes the facts from its next start. Absent
            when nothing was written.
      examples:
        - written:
            - id: 7d1e3a5c-9b2f-4e6a-8c0d-2f4a6c8e0b2d
              kind: memory
              scope: repository
              owner: local
              title: Migrations and the schema document are one change
              body: A new migration without its schema block fails two tests.
              state: active
              origin: loop
              createdAt: '2026-09-07T09:12:00.000Z'
              hits: 0
          refused: []
          appliedToSessionId: 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d
    RefinementMark:
      type: object
      description: One item's answer, named by the index the round sent.
      required:
        - index
        - accepted
      properties:
        index:
          type: integer
          format: int32
          minimum: 0
          description: >-
            The item's position in the round exactly as the engine sent it. A
            client that reordered the items would post somebody's approval onto
            a different edit.
        accepted:
          type: boolean
      examples:
        - index: 0
          accepted: true
    Refinement:
      type: object
      description: >-
        One thing the harness learned and a person allowed: a distilled memory,
        or a skill, agent or command definition the model authored.

        The owner is never something a caller names.

        `script` and `events` are present on getRefinement and absent from the
        listing. A page carrying every authored program's source is a page
        nobody can read; the hash is on both, which is what "what was consented
        to is what runs" is checked against.
      required:
        - id
        - kind
        - scope
        - owner
        - title
        - body
        - state
        - origin
        - createdAt
        - hits
      properties:
        id:
          type: string
          format: uuid
        kind:
          $ref: '#/components/schemas/RefinementKind'
        scope:
          $ref: '#/components/schemas/RefinementScope'
        repository:
          type: string
          description: The canonical checkout path, absent at the owner's global scope.
        owner:
          type: string
          description: Whose learning this is.
        name:
          type: string
          description: >-
            The ladder identity of the three definition kinds, absent on a
            memory.
          maxLength: 128
        title:
          type: string
          maxLength: 200
        body:
          type: string
          description: The fact's text, or the definition's prompt or description.
        script:
          type: string
          description: >-
            The program the model wrote, IN FULL — never a digest and never a
            path. A person cannot consent to what they were not shown, and what
            they consented to is what the confined runtime later runs, byte for
            byte. Present on getRefinement only.
        scriptSha256:
          type: string
          description: >-
            The hash of that program, on the listing as well as the read. It is
            what the runtime checks the text against before running it.
          pattern: ^[0-9a-f]{64}$
        state:
          $ref: '#/components/schemas/RefinementState'
        origin:
          $ref: '#/components/schemas/RefinementOrigin'
        originSessionId:
          type: string
          description: >-
            The conversation this was learned from. It may name a session that
            has since been purged, which is what `unverifiable` reads from.
        originEntryId:
          type: string
          description: The turn this was learned in.
        originActor:
          type: string
          description: Who was acting when this came in over the contract.
        citations:
          type: array
          description: The turns this stands on, in the order they were written.
          items:
            $ref: '#/components/schemas/RefinementCitation'
        events:
          type: array
          description: >-
            Everything that has happened to this refinement, newest first.
            Present on getRefinement only.
          items:
            $ref: '#/components/schemas/RefinementEventEntry'
        createdAt:
          type: string
          format: date-time
        activatedAt:
          type: string
          format: date-time
          description: When a person consented. Absent while pending.
        lastUsedAt:
          type: string
          format: date-time
          description: >-
            When this last fired into a prompt. It is what eviction is ordered
            by — a fact that fires often is a fact that earned its place — and
            it is deliberately never rewound by a rollback.
        hits:
          type: integer
          format: int32
          minimum: 0
          description: How many turns this has fired into.
        supersededBy:
          type: string
          format: uuid
          description: The row that replaced this one, if any.
      examples:
        - id: 7d1e3a5c-9b2f-4e6a-8c0d-2f4a6c8e0b2d
          kind: memory
          scope: repository
          repository: /Users/dana/repos/midaz
          owner: local
          title: Migrations and the schema document are one change
          body: >-
            A new migration file without the matching block in schema.sql fails
            two tests the moment it lands.
          state: active
          origin: loop
          originSessionId: 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d
          originEntryId: 8a1d3f5b-7c9e-4a2b-8d6f-0c2e4a6b8d0f
          citations:
            - sessionId: 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d
              entryId: 8a1d3f5b-7c9e-4a2b-8d6f-0c2e4a6b8d0f
          createdAt: '2026-09-07T09:12:00.000Z'
          activatedAt: '2026-09-07T09:12:00.000Z'
          hits: 4
    RefinementRefusal:
      type: object
      description: >-
        One accepted mark that did not become a row, and why. It is reported
        rather than raised: a round is answered as a whole, so one edit narya
        cannot apply must not throw away the person's answer to the other four.


        Usually a judgment — a verb this host does not apply at consent, a
        baseline the ledger has moved past, a name no ladder could resolve. It
        is also where a STORE fault lands when one arrives part way through a
        round: the answer is settled and cannot be given again, so the item the
        ledger would not take is named here with the store's own words, and
        nothing after it in the round was attempted.
      required:
        - index
        - reason
      properties:
        index:
          type: integer
          format: int32
          minimum: 0
        reason:
          type: string
      examples:
        - index: 2
          reason: a repository-scoped fact was proposed in a round with no repository
    Error:
      type: object
      description: >-
        The single error envelope every operation returns. Codes are NRY-
        followed by four digits and are catalogued in the top-level
        x-error-catalog extension.
      required:
        - code
        - title
        - message
      properties:
        code:
          type: string
          pattern: ^NRY-[0-9]{4}$
          description: Machine-readable error code from the NRY catalogue.
        title:
          type: string
          maxLength: 256
          description: Short human-readable summary of the error class.
        message:
          type: string
          maxLength: 4096
          description: Specific, actionable description of what went wrong.
        fields:
          type: object
          description: Per-field validation problems.
          additionalProperties:
            type: string
      examples:
        - code: NRY-0002
          title: Session not found
          message: >-
            No session with id 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d exists on
            this host.
    RefinementKind:
      type: string
      enum:
        - memory
        - skill
        - agent
        - command
      x-enum-varnames:
        - RefinementKindMemory
        - RefinementKindSkill
        - RefinementKindAgent
        - RefinementKindCommand
      description: >-
        What a refinement IS. Four values and no more — one vocabulary is what
        makes "everything this repository taught narya" one question.
    RefinementScope:
      type: string
      enum:
        - repository
        - global
      x-enum-varnames:
        - RefinementScopeRepository
        - RefinementScopeGlobal
      description: >-
        How far a refinement reaches. `repository` is keyed on the canonical
        checkout path, the same key a trust answer uses; `global` is the
        owner's.

        There is no `session` here and the absence is a decision: a
        session-scoped fact lives exactly as long as the conversation that gave
        it, so it is never a stored row at all.
    RefinementState:
      type: string
      enum:
        - pending
        - active
        - rolled-back
        - unverifiable
      x-enum-varnames:
        - RefinementStatePending
        - RefinementStateActive
        - RefinementStateRolledBack
        - RefinementStateUnverifiable
      description: >-
        Where a refinement stands. `pending` is proposed and nothing else —
        never rendered, never executed, never on a ladder. `active` is consented
        and firing. `rolled-back` is kept for the record.

        `unverifiable` is the one that surprises: such a fact is STILL FIRING
        and says so. Every session it cited has been purged, which is a person
        deleting a transcript rather than a person retracting a belief.
    RefinementOrigin:
      type: string
      enum:
        - loop
        - api
        - import
      x-enum-varnames:
        - RefinementOriginLoop
        - RefinementOriginApi
        - RefinementOriginImport
      description: >-
        Which road a refinement came in on: narya's own review of a
        conversation, a client teaching it through this contract, or an import.
        Both roads land pending and pass the same consent.
    RefinementCitation:
      type: object
      description: >-
        One pointer into the transcript that justifies a refinement. The
        admitted user entry's id IS the turn id, so citing the turns needs no
        second identifier.

        THE POINTER MAY DANGLE, and that is the design: nothing cascades from a
        purged session to a fact learned in it, because a person deleting one
        noisy conversation must not silently lose weeks of learning. A fact
        whose evidence is gone becomes `unverifiable` and keeps firing.
      required:
        - sessionId
        - entryId
      properties:
        sessionId:
          type: string
          format: uuid
        entryId:
          type: string
          format: uuid
        note:
          type: string
          description: What the review said about this turn.
          maxLength: 2000
      examples:
        - sessionId: 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d
          entryId: 8a1d3f5b-7c9e-4a2b-8d6f-0c2e4a6b8d0f
          note: the third attempt at the same import cycle
    RefinementEventEntry:
      type: object
      description: >-
        One thing that happened to one refinement. The log is APPEND-ONLY:
        nothing in it is ever updated or deleted, because "who taught narya
        this, and who took it away" has to be answerable from the log alone.
      required:
        - id
        - action
        - at
      properties:
        id:
          type: string
          format: uuid
        action:
          $ref: '#/components/schemas/RefinementAction'
        actor:
          type: string
          description: Who acted. Empty when narya's own loop did.
        at:
          type: string
          format: date-time
        causedByEventId:
          type: string
          format: uuid
          description: >-
            The event this one inverts, absent when it inverts nothing. It is
            what makes a rollback of a rollback readable as a redo.
      examples:
        - id: 5c7e9a1b-3d5f-4a7c-9e1b-3d5f7a9c1e3b
          action: activated
          actor: local
          at: '2026-09-07T09:12:00.000Z'
    RefinementAction:
      type: string
      enum:
        - created
        - activated
        - updated
        - promoted
        - demoted
        - rolled-back
        - deleted
      x-enum-varnames:
        - RefinementActionCreated
        - RefinementActionActivated
        - RefinementActionUpdated
        - RefinementActionPromoted
        - RefinementActionDemoted
        - RefinementActionRolledBack
        - RefinementActionDeleted
      description: >-
        What happened to a refinement. There is no `restored`: restoring what
        somebody undid is a rollback OF a rollback, so undo and redo are one
        verb aimed at different events and the log nests instead of branching.
  responses:
    BadRequest:
      description: Malformed request — invalid parameter, cursor, or JSON body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The addressed resource does not exist on this host.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: >-
        The resource's current state rejects the request — archived session,
        busy lane, slot conflict, failed build, already-final state.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RequestBodyTooLarge:
      description: >-
        The request body weighs more than this operation accepts (NRY-0024). The
        host holds one ceiling per operation and refuses at the door, in front
        of every handler: a body whose declared Content-Length is past the
        ceiling is refused before a byte of it is read, and a body that declares
        no length is read only as far as the ceiling and refused there. Nothing
        was read past that point and nothing was written.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnprocessableEntity:
      description: The request was well-formed but failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalServerError:
      description: The host failed — including a store that refuses writes (NRY-0012).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Enforced on every transport, with no exempt operation. A person's
        request — over the default local unix socket exactly as over a TCP
        listener — must carry a JWT issued by the configured identity provider,
        which the host verifies itself against that issuer's key set: signature,
        issuer, expiry, and the person and organisation it names. Requests
        without a valid one receive 401 NRY-0011. The socket's file permissions
        are transport and are not an authorisation.

````