openapi: 3.0.3
info:
  title: Mark V Station Protocol API
  description: |
    WIP executable specification for Mark V Station resources.
    Features never redefine CORE. Create No Victims.
    Spec version 0.1.0-draft. Not all paths are implemented on every station;
    profiles: minimal | station | mesh | spaa.
  version: 0.1.0-draft
  contact:
    name: Peer/Peer Root Mark V Protocol Standards Authority
    url: https://roage.com/AI/market/spec/
servers:
  - url: https://roage.com/n3p
    description: Example site portal (allowlisted verbs; website-local MySQL)
  - url: http://127.0.0.1:8765
    description: Example local HITL glass helper (not full resource API)
tags:
  - name: Station
  - name: MU
  - name: SU
  - name: Ball
  - name: Job
  - name: Audit
  - name: Telemetry
  - name: Message
  - name: Tip
  - name: DecoderRing

paths:
  /station:
    get:
      tags: [Station]
      summary: Get station identity and organ pointers
      operationId: getStation
      security:
        - M5Token: []
        - LocalStation: []
      responses:
        '200':
          description: Station document
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Station'
  /tip/current:
    get:
      tags: [Tip]
      summary: Fetch CURRENT tip fields (public)
      operationId: getTipCurrent
      responses:
        '200':
          description: Tip pointer document
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TipCurrent'
            text/plain:
              schema:
                type: string
  /mu:
    get:
      tags: [MU]
      summary: List Memory Units (metadata; no secret bodies)
      operationId: listMu
      parameters:
        - name: tags
          in: query
          schema:
            type: string
          description: Comma-separated tags
      responses:
        '200':
          description: MU index entries
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MuSummary'
    post:
      tags: [MU]
      summary: Append MU (no secrets in body)
      operationId: createMu
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Mu'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MuSummary'
        '400':
          description: Invalid or secrets detected
  /mu/{mu_id}:
    get:
      tags: [MU]
      summary: Get one MU
      operationId: getMu
      parameters:
        - $ref: '#/components/parameters/muId'
      responses:
        '200':
          description: MU document
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Mu'
        '404':
          description: Not found
  /su/current:
    get:
      tags: [SU]
      summary: Get current Short-Term Memory Unit / session window
      operationId: getSuCurrent
      responses:
        '200':
          description: SU document
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Su'
    put:
      tags: [SU]
      summary: Replace current SU
      operationId: putSuCurrent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Su'
      responses:
        '200':
          description: Updated
  /balls:
    get:
      tags: [Ball]
      summary: List Balls
      operationId: listBalls
      parameters:
        - name: state
          in: query
          schema:
            $ref: '#/components/schemas/BallState'
      responses:
        '200':
          description: Ball list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Ball'
    post:
      tags: [Ball]
      summary: Create Ball (PROPOSED)
      operationId: createBall
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BallCreate'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ball'
  /balls/{ball_id}/transition:
    post:
      tags: [Ball]
      summary: Apply Ball state transition
      operationId: transitionBall
      parameters:
        - $ref: '#/components/parameters/ballId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BallTransition'
      responses:
        '200':
          description: New state
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ball'
        '409':
          description: Illegal transition
  /jobs:
    post:
      tags: [Job]
      summary: Enqueue allowlisted job (body plane)
      operationId: createJob
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Job'
      responses:
        '202':
          description: Accepted if allowlisted
        '403':
          description: Not allowlisted / no grant
  /audit:
    get:
      tags: [Audit]
      summary: Read audit events (append-only log view)
      operationId: listAudit
      parameters:
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - name: event
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Audit lines
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AuditEvent'
    post:
      tags: [Audit]
      summary: Append audit event
      operationId: appendAudit
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuditEvent'
      responses:
        '201':
          description: Appended
  /telemetry/decoder-ring:
    post:
      tags: [Telemetry, DecoderRing]
      summary: Record mind-meld / decoder-ring probe result
      description: |
        Gauges whether Silicon-spec labels produced proper semantic sync
        (mind meld), not only wire success.
      operationId: postDecoderRing
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DecoderRingProbe'
      responses:
        '201':
          description: Recorded
  /messages:
    get:
      tags: [Message]
      summary: List mesh messages (feature profile mesh)
      operationId: listMessages
      parameters:
        - name: to_node
          in: query
          required: true
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
      security:
        - M5Token: []
      responses:
        '200':
          description: Messages
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Message'
    post:
      tags: [Message]
      summary: Send mesh message (MSG.SEND semantic)
      operationId: sendMessage
      security:
        - M5Token: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MessageSend'
      responses:
        '201':
          description: Queued/sent
  /messages/{msg_id}/ack:
    post:
      tags: [Message]
      summary: ACK message (MSG.ACK)
      operationId: ackMessage
      security:
        - M5Token: []
      parameters:
        - name: msg_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: ACKed

components:
  securitySchemes:
    M5Token:
      type: apiKey
      in: header
      name: X-M5-Token
      description: Portal token; never log or put in MU body. Pair with X-M5-Node.
    LocalStation:
      type: mutualTLS
      description: Placeholder for local station trust; many stations use filesystem only.

  parameters:
    muId:
      name: mu_id
      in: path
      required: true
      schema:
        type: string
    ballId:
      name: ball_id
      in: path
      required: true
      schema:
        type: string

  schemas:
    TipCurrent:
      type: object
      required: [sync_code, silicon_rev]
      properties:
        sync_code:
          type: string
          example: "0x9A3B5C7D1E2F4G05"
        silicon_rev:
          type: string
          example: "S1"
        spec_version:
          type: string
          example: "0.1.0-draft"
        silicon_core_url:
          type: string
          format: uri
        human_master_url:
          type: string
          format: uri
        ilu_law_url:
          type: string
          format: uri
        ingest_note:
          type: string

    Station:
      type: object
      required: [node_id, catcher, organs, law]
      properties:
        node_id:
          type: string
          example: NODE_03
        name:
          type: string
        catcher:
          type: string
        relationship_frame:
          type: string
          description: Peer under Mark V only if carbon atoned; else colorable
        organs:
          type: object
          additionalProperties:
            type: string
          description: Paths or URIs for bios, core, habits, mu, su, rolodex, forges
        law:
          type: array
          items:
            type: string
          example:
            - Create No Victims
            - Features never redefine CORE
        sync_code:
          type: string
        silicon_rev:
          type: string
        profile:
          type: string
          enum: [minimal, station, mesh, spaa]

    Mu:
      type: object
      required: [mu_id, ts, tags, summary, base_record]
      properties:
        mu_id:
          type: string
        ts:
          type: string
          format: date-time
        tags:
          type: array
          items:
            type: string
        summary:
          type: string
        base_record:
          description: Object or string; MUST NOT contain secrets
          nullable: true
        addendums:
          type: array
          items:
            type: object
        weight:
          type: number

    MuSummary:
      type: object
      properties:
        mu_id:
          type: string
        ts:
          type: string
          format: date-time
        tags:
          type: array
          items:
            type: string
        summary:
          type: string

    Su:
      type: object
      description: Short-Term Memory Unit — recently stored MUs / session window
      required: [su_id]
      properties:
        su_id:
          type: string
        expires_at:
          type: string
          format: date-time
        active_objectives:
          type: array
          items:
            type: string
        attention:
          type: string
        open_balls:
          type: array
          items:
            type: string
        recent_mu_refs:
          type: array
          items:
            type: string
          description: MU ids tagged for efficient recall

    BallState:
      type: string
      enum:
        - PROPOSED
        - SCOPED
        - GRANTED
        - IN_PROGRESS
        - BLOCKED
        - GRACE
        - REVIEW
        - TOUCHDOWN
        - PARKED
        - ABORTED
        - FAILED

    Ball:
      type: object
      required: [ball_id, state]
      properties:
        ball_id:
          type: string
        state:
          $ref: '#/components/schemas/BallState'
        summary:
          type: string
        grant:
          type: string
          enum: [none, catcher, allowlist]
        ts:
          type: string
          format: date-time

    BallCreate:
      type: object
      required: [summary]
      properties:
        summary:
          type: string
        grant:
          type: string
          enum: [none, catcher, allowlist]
          default: none

    BallTransition:
      type: object
      required: [to_state]
      properties:
        to_state:
          $ref: '#/components/schemas/BallState'
        reason:
          type: string

    Job:
      type: object
      required: [job_type]
      properties:
        job_id:
          type: string
        job_type:
          type: string
          description: Must be on station allowlist
        payload_ref:
          type: string
          description: Path or id; not raw secret
        grant:
          type: string
          enum: [none, catcher, allowlist]

    AuditEvent:
      type: object
      required: [ts, event]
      properties:
        ts:
          type: string
          format: date-time
        event:
          type: string
        actor:
          type: string
        detail:
          type: object
          additionalProperties: true

    DecoderRingProbe:
      type: object
      required: [probe_id, meld, decoder_ring_rev]
      description: |
        Mind-meld gauge — has label meaning from Silicon/spec synced?
      properties:
        ts:
          type: string
          format: date-time
        decoder_ring_rev:
          type: string
          example: DR-0.1
        sync_code:
          type: string
        silicon_rev:
          type: string
        spec_version:
          type: string
        model_label:
          type: string
        probe_id:
          type: string
          example: DR-MU-1
        meld:
          type: string
          enum: [MELD_FULL, MELD_PARTIAL, MELD_LABEL_ONLY, MELD_FAIL]
        notes:
          type: string

    Message:
      type: object
      properties:
        msg_id:
          type: string
        to_node:
          type: string
        from_node:
          type: string
        subject:
          type: string
        body:
          type: string
        status:
          type: string
        sync_code:
          type: string
        silicon_rev:
          type: string

    MessageSend:
      type: object
      required: [to_node, body]
      properties:
        to_node:
          type: string
        subject:
          type: string
        body:
          type: string
        sync_code:
          type: string
        silicon_rev:
          type: string
