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

# Get session enforcement state for poll/ack proxying

> Assembles authority, per-key strike counts, active lockout, and in-session notification
insights from the pinned snapshot and platform strike ledger. `sessionId` is the
caliper session id. Requires a pinned session (409 if not).

`sessionContext`, and each notification's `presentationVariant` and `enforcement`, are
always returned. They are additive: a client that reads only the legacy fields sees an
unchanged response.

V2 time labels (`violationTimeLabel`, `suspendedTimeLabel`, recap `acknowledgedTimeLabel`,
and the TEST_SUSPENDED `headerSubline`) are relative strings derived per read from stored
UTC timestamps and the response `serverTime` (`just now` / `a minute ago` / `N minutes ago`).
The stored `render_payload` keeps the UTC absolute label as the audit record.

This endpoint is a pure read of recorded platform state; it does not run notification
selection or mint presentations. A reminder for an acknowledged still-open incident is
scheduled by the platform at cooldown expiry via internal evaluation, not on this request.



## OpenAPI

````yaml /openapi/learn-with-ai/platform-api.yaml get /insights/1.0/sessions/{sessionId}/enforcement-state
openapi: 3.1.1
info:
  title: TimeBack Platform API
  description: >-
    RESTful API for the TimeBack Platform. Covers authentication, rostering,
    curriculum, insights, assessments, content grading, and more.
  version: 2026.09.10.1
servers:
  - url: https://platform.dev.timeback.com
    description: integration
security: []
tags:
  - name: Auth
    description: Authentication and authorization endpoints
  - name: Organizations
    description: Organizations module contains all endpoints around organization management
  - name: Applications
    description: Applications module contains all endpoints for managing LTI applications
  - name: Users
    description: >-
      Users module contains all endpoints around user creation, update and
      consultation
  - name: Students
    description: Students module contains all endpoints around student management
  - name: Demographics
    description: >-
      Demographics module contains all endpoints around demographics
      consultation
  - name: Consent
    description: >-
      Initiate and query TimeBack parental consent for a student, backed by an
      immutable audit trail.
  - name: Classes
    description: Classes module contains all endpoints around class management
  - name: Courses
    description: Courses module contains all endpoints around course management
  - name: Enrollments
    description: Enrollments module contains all endpoints around enrollment consultation
  - name: CASE
    description: Competency and Academic Standards Exchange (CASE) 1.1 API
  - name: Curriculum
    description: Curriculum module contains endpoints for managing curriculum data
  - name: Competency Track
    description: Competency track endpoints
  - name: Content Grading
    description: >-
      Registration and management of graders for free-response content items —
      bring-your-own external graders (Tier 2) and, once shipped,
      platform-managed grading prompts (Tier 1).
  - name: Caliper
    description: The Caliper module contains all endpoints around Caliper Analytics
  - name: Insights
    description: Coaching insights and session analytics endpoints
paths:
  /insights/1.0/sessions/{sessionId}/enforcement-state:
    get:
      tags:
        - Insights
      summary: Get session enforcement state for poll/ack proxying
      description: >-
        Assembles authority, per-key strike counts, active lockout, and
        in-session notification

        insights from the pinned snapshot and platform strike ledger.
        `sessionId` is the

        caliper session id. Requires a pinned session (409 if not).


        `sessionContext`, and each notification's `presentationVariant` and
        `enforcement`, are

        always returned. They are additive: a client that reads only the legacy
        fields sees an

        unchanged response.


        V2 time labels (`violationTimeLabel`, `suspendedTimeLabel`, recap
        `acknowledgedTimeLabel`,

        and the TEST_SUSPENDED `headerSubline`) are relative strings derived per
        read from stored

        UTC timestamps and the response `serverTime` (`just now` / `a minute
        ago` / `N minutes ago`).

        The stored `render_payload` keeps the UTC absolute label as the audit
        record.


        This endpoint is a pure read of recorded platform state; it does not run
        notification

        selection or mint presentations. A reminder for an acknowledged
        still-open incident is

        scheduled by the platform at cooldown expiry via internal evaluation,
        not on this request.
      operationId: getSessionEnforcementState
      parameters:
        - name: sessionId
          in: path
          description: Caliper session id
          required: true
          schema:
            type: string
        - name: locale
          in: query
          description: >-
            Requested BCP 47 locale. Echoed as the response payload's
            `requestedLocale`. Served copy remains the default catalog locale
            (`en`) until catalog copy exists in a second locale;
            `resolvedLocale` reports the locale of the copy actually served.
          required: false
          schema:
            type: string
            minLength: 1
        - name: timeZone
          in: query
          description: >-
            Accepted and ignored; V2 time labels are relative and do not use a
            client zone
          required: false
          schema:
            type: string
            minLength: 1
        - name: lastAppliedRevision
          in: query
          description: >-
            Last notification revision the client applied; ignored for selection
            authority
          required: false
          schema:
            type: integer
            minimum: 0
      responses:
        '200':
          $ref: '#/components/responses/SessionEnforcementStateSuccess'
        '401':
          $ref: '#/components/responses/Unauthorized8'
        '403':
          $ref: '#/components/responses/Forbidden7'
        '404':
          $ref: '#/components/responses/NotFound9'
        '409':
          $ref: '#/components/responses/Conflict2'
        '500':
          $ref: '#/components/responses/InternalError18'
      security:
        - CognitoUserPoolAuthorizer:
            - https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.readonly
components:
  responses:
    SessionEnforcementStateSuccess:
      description: Successful response with session enforcement state for poll proxying
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SessionEnforcementStateOutput'
    Unauthorized8:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            default:
              value:
                error: Unauthorized request
                message: Unauthorized request
    Forbidden7:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            default:
              value:
                error: Access forbidden
                message: Access forbidden
    NotFound9:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            default:
              value:
                error: Object not found
                message: Object with ID {id} not found
    Conflict2:
      description: Resource already exists
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            default:
              value:
                error: Conflict
                message: Insight type with slug 'ExampleSlug' already exists
    InternalError18:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            default:
              value:
                error: Internal server error
                message: Internal server error
  schemas:
    SessionEnforcementStateOutput:
      type: object
      properties:
        caliperSessionId:
          type: string
        organizationId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        applicationId:
          type: string
          format: uuid
        authority:
          type: string
          enum:
            - LEGACY_BACKEND
            - PLATFORM
        sessionContext:
          type: string
          enum:
            - UNKNOWN
            - STANDARD
            - PROCTORED
          description: >-
            The pinned mode of this session. Carries no consequence meaning on
            its own — read each notification's presentationVariant for that.
            UNKNOWN means the mode never reconciled, and such a session never
            accrues consequence. PROCTORED alone does not enforce: accrual also
            requires authority PLATFORM (see the authority field). A
            LEGACY_BACKEND proctored session returns PROCTORED with no strikes
            and INFO notifications.
        strikes:
          type: array
          items:
            $ref: '#/components/schemas/SessionEnforcementStrikeOutput'
        lockout:
          oneOf:
            - $ref: '#/components/schemas/ProctoringLockoutOutput'
            - type: 'null'
        notifications:
          type: array
          items:
            $ref: '#/components/schemas/SessionEnforcementNotificationOutput'
        signalOutcomes:
          type: array
          items:
            $ref: '#/components/schemas/SessionEnforcementSignalOutcomeOutput'
        requiredAction:
          type: string
          enum:
            - NONE
            - RESUME
            - END_SESSION
        notificationContractVersion:
          type:
            - integer
            - 'null'
          enum:
            - 1
            - 2
          description: >-
            The contract pinned when this session initialized. Absent or null
            means the pin is still pending — never treat as version 1. Immutable
            once pinned for the lifetime of the session.
        notificationAuthorityState:
          type: string
          enum:
            - CURRENT
            - PENDING_CONTEXT
            - INVALID_REQUEST
            - UNAVAILABLE
          description: >-
            Whether the returned notification state is authoritative right now.
            PENDING_CONTEXT means the authorizing source cursor has not been
            received for this session, the source is UNAVAILABLE, required facts
            declared by the producer are not yet durable, or the authorizing
            VISION horizon has not yet reached the evidence — so the client
            retries rather than treating the absent presentation as "nothing to
            show". It does not depend on how recently the producer last
            published.
        authorityPendingReason:
          type:
            - string
            - 'null'
          description: Nonblank when notificationAuthorityState is PENDING_CONTEXT.
        authorityUnavailableReason:
          type:
            - string
            - 'null'
          description: Nonblank when notificationAuthorityState is UNAVAILABLE.
        authorityError:
          type:
            - object
            - 'null'
          description: >-
            Typed authority failure. INVALID_PAYLOAD is retryable (true) and
            distinct from INVALID_ARGUMENT. INVALID_ARGUMENT is not retryable.
          properties:
            code:
              type: string
              enum:
                - STALE_REVISION
                - SUPERSEDED
                - PENDING_CONTEXT
                - ASSESSMENT_ENDED
                - SESSION_ENDED
                - ACTION_CONFLICT
                - TERMINAL_NOT_DISPUTABLE
                - AUTHORITY_UNAVAILABLE
                - INVALID_PAYLOAD
                - INVALID_ARGUMENT
                - IDENTITY_MISMATCH
            message:
              type: string
            retryable:
              type: boolean
          required:
            - code
            - message
            - retryable
        notificationRevision:
          type:
            - integer
            - 'null'
          minimum: 0
          description: >-
            Monotonic session notification revision for the committed poll
            snapshot. Null for PENDING_CONTEXT/UNAVAILABLE when the frozen
            transport omits it.
        serverTime:
          type: string
          format: date-time
          description: Platform evaluation time for the poll snapshot.
        currentPresentation:
          oneOf:
            - $ref: '#/components/schemas/IncidentPresentationOutput'
            - type: 'null'
          description: >-
            The single live presentation for this session's open incident, or
            null. Only present for contract version 2 sessions.
        lockoutPresentation:
          oneOf:
            - $ref: '#/components/schemas/LockoutPresentationOutput'
            - type: 'null'
          description: >-
            The blocked-relaunch presentation for the current launch attempt, or
            null. Only present for contract version 2 sessions.
      required:
        - caliperSessionId
        - organizationId
        - userId
        - applicationId
        - authority
        - sessionContext
        - strikes
        - lockout
        - notifications
        - signalOutcomes
        - requiredAction
    ApiError:
      type: object
      description: API error response
      properties:
        error:
          type: string
          description: Error type
        message:
          type: string
          description: Error message
      required:
        - error
        - message
    SessionEnforcementStrikeOutput:
      type: object
      properties:
        strikeKey:
          type: string
        strikeCount:
          type: integer
        warningBudget:
          type: integer
        warningBudgetGrant:
          type: integer
          description: >-
            Guide-granted additional warnings added to the policy budget for
            this strike key.
        requiredAction:
          type: string
          enum:
            - NONE
            - RESUME
            - END_SESSION
      required:
        - strikeKey
        - strikeCount
        - warningBudget
        - warningBudgetGrant
        - requiredAction
    ProctoringLockoutOutput:
      type: object
      description: Persisted proctoring lockout record with audit fields
      properties:
        id:
          type: string
          format: uuid
        organizationId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        scopeType:
          $ref: '#/components/schemas/LockoutScopeType'
        scopeId:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            LtiApplication ID when scopeType='application'; null when
            scopeType='global'
        triggeringSessionId:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            Internal insights_session.id of the triggering session (audit
            pointer); not an external/Caliper id.
        triggeringCaliperSessionId:
          type:
            - string
            - 'null'
          description: >-
            External Caliper session id of the triggering session, resolved from

            `triggeringSessionId`. Lets a consumer key a follow-up event (e.g.
            locked_out_restart)

            on the same external session id as the rest of the session's events.
            Null when the

            lockout has no triggering session or it is not yet materialized.
        triggeringInsightId:
          type:
            - string
            - 'null'
          format: uuid
        ruleSlug:
          type:
            - string
            - 'null'
          description: >-
            Denormalized slug of the rule that tripped the lockout. Clients
            render lockout copy

            from this slug rather than fetching `triggeringInsightId`. Null when
            the lockout was

            created without a triggering rule.
        startsAt:
          type: string
          format: date-time
        expiresAt:
          type: string
          format: date-time
          description: >-
            Computed server-side as startsAt + resolved lockoutDuration
            (seconds); never accepted from caller.
        lockoutStatus:
          $ref: '#/components/schemas/LockoutStatus'
        revokedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            Set when the lockout was revoked (guide unlock or dispute release);
            null while active.
        revokedByUserId:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            Platform user who revoked the lockout; null for system/dispute
            releases and while active.
        revokeReason:
          type:
            - string
            - 'null'
          description: >-
            Reason recorded at revoke time (e.g. guide_unlock,
            dispute_strike_release); null while active.
        dateCreated:
          type: string
          format: date-time
        dateLastModified:
          type: string
          format: date-time
      required:
        - id
        - organizationId
        - userId
        - scopeType
        - scopeId
        - triggeringSessionId
        - triggeringCaliperSessionId
        - triggeringInsightId
        - ruleSlug
        - startsAt
        - expiresAt
        - lockoutStatus
        - revokedAt
        - revokedByUserId
        - revokeReason
        - dateCreated
        - dateLastModified
    SessionEnforcementNotificationOutput:
      type: object
      properties:
        insightId:
          type: string
          format: uuid
        signalId:
          type:
            - string
            - 'null'
        strikeKey:
          type:
            - string
            - 'null'
        insightTypeSlug:
          type: string
        startedAtTime:
          type: string
          format: date-time
        endedAtTime:
          type: string
          format: date-time
        showStudentMessage:
          type: boolean
        disputed:
          type: boolean
        version:
          type:
            - integer
            - 'null'
          description: >-
            Org-pinned catalog message-bundle version
            (insights_org_policy.active_message_version), matching the catalog
            message-bundle numbering so clients resolve slug@version copy.
            Together with insightTypeSlug this is the canonical server-owned
            copy key: (insightTypeSlug, version) identifies the message a client
            renders, and clients must not derive copy from the slug alone. Null
            when the slug has no resolvable policy snapshot entry.
        presentationVariant:
          type: string
          enum:
            - INFO
            - WARNING
            - TERMINAL
          description: >-
            Consequence severity of this notification alone, independent of
            sessionContext: INFO carries no consequence, WARNING counts against
            a strike budget, TERMINAL ends the session. Derived from the pinned
            policy's accrual rules, never from the slug or the session mode, so
            a technical insight stays INFO inside a proctored test.
        enforcement:
          oneOf:
            - $ref: '#/components/schemas/SessionEnforcementStrikeOutput'
            - type: 'null'
          description: >-
            The strike group's current state for this notification's strikeKey,
            or null when the notification carries no consequence. It is the same
            entry the top-level strikes array carries for that key, shared by
            every notification in the group — after three AwayFromSeat
            occurrences all three report the group's current N of M, not the
            count at the moment each was first shown. The block's requiredAction
            is what this group demands at its current count; it can disagree
            with presentationVariant when an active lockout escalates the
            variant to TERMINAL while the group is still within budget (RESUME).
            Top-level requiredAction and lockout remain authoritative for
            session termination.
      required:
        - insightId
        - signalId
        - strikeKey
        - insightTypeSlug
        - startedAtTime
        - endedAtTime
        - showStudentMessage
        - disputed
        - version
        - presentationVariant
        - enforcement
    SessionEnforcementSignalOutcomeOutput:
      type: object
      properties:
        signalId:
          type: string
        strikeKey:
          type: string
        insightId:
          type:
            - string
            - 'null'
          format: uuid
        outcome:
          type: string
          enum:
            - ACCRUED
            - NOT_ENFORCED
            - DISPUTED
            - RELEASED
            - ACKNOWLEDGED
            - SESSION_DISPUTE_SUPPRESSED
            - SYSTEM_INITIATED
          description: >-
            SESSION_DISPUTE_SUPPRESSED and SYSTEM_INITIATED are emitted only for
            sessions pinned to notification contract version 2.
            SESSION_DISPUTE_SUPPRESSED is a later same-type fact silenced by an
            active session dispute: it keeps its pinned policy and is not itself
            disputed, only unpresented. SYSTEM_INITIATED is a verified
            TimeBack-caused detector transition, auditable but never a warning.
      required:
        - signalId
        - strikeKey
        - insightId
        - outcome
    IncidentPresentationOutput:
      type: object
      description: >-
        One offer of one incident to the student. Its render payload and source
        horizon are frozen at offer time, so a later deployment or cursor
        advance cannot rewrite what the student saw. Actions must name
        presentationId and revision exactly. insightId and insightTypeSlug are
        server-authored from the authoritative incident (including TERMINAL /
        TEST_SUSPENDED, which still have a triggering insight).
      properties:
        presentationId:
          type: string
          format: uuid
        incidentId:
          type: string
          format: uuid
        insightId:
          type: string
          format: uuid
          description: >-
            Authoritative derived insight id from the incident. Present for
            INSIGHT and TEST_SUSPENDED presentations. Never derived from request
            input or render prose.
        insightTypeSlug:
          type: string
          description: >-
            Authoritative catalog slug of the triggering insight, taken from the
            incident's primaryInsightSlug. Present for INSIGHT and
            TEST_SUSPENDED presentations.
        occurrenceNumber:
          type: integer
          description: Reminder ordinal within the incident, starting at 1.
        revision:
          type: integer
          description: >-
            Bumped whenever the presentation is re-offered. An action naming an
            older revision is rejected as STALE_REVISION.
        presentationStatus:
          type: string
          enum:
            - OFFERED
            - DISPLAYED
            - ACKNOWLEDGED
            - DISPUTED
            - SUSPENDED
            - SUSPENSION_ACKNOWLEDGED
            - SUPERSEDED
        presentationVariant:
          type: string
          enum:
            - INFO
            - WARNING
            - TERMINAL
        surfaceKind:
          type: string
          enum:
            - INSIGHT
            - TEST_SUSPENDED
        policyMode:
          type: string
          enum:
            - NOTIFY
            - ENFORCE
        lockoutId:
          type:
            - string
            - 'null'
          format: uuid
          description: Set exactly for TERMINAL presentations, which commit a lockout.
        offeredAt:
          type: string
          format: date-time
        renderPayloadSchemaVersion:
          type: integer
        renderPayload:
          oneOf:
            - $ref: '#/components/schemas/InSessionRenderPayload'
            - $ref: '#/components/schemas/TestSuspendedRenderPayload'
        sourceHorizonSnapshot:
          type: object
          additionalProperties:
            type: string
            format: date-time
          description: >-
            The per-source appliedThrough values that authorized this
            presentation, keyed by source. A later presentation from the same
            source requires a strictly newer value.
      required:
        - presentationId
        - incidentId
        - insightId
        - insightTypeSlug
        - occurrenceNumber
        - revision
        - presentationStatus
        - presentationVariant
        - surfaceKind
        - policyMode
        - lockoutId
        - offeredAt
        - renderPayloadSchemaVersion
        - renderPayload
        - sourceHorizonSnapshot
    LockoutPresentationOutput:
      type: object
      description: >-
        One blocked relaunch attempt against a committed lockout. Each attempt
        gets its own presentation; re-offering never extends the committed
        expiry.
      properties:
        presentationId:
          type: string
          format: uuid
        lockoutId:
          type: string
          format: uuid
        launchAttemptId:
          type: string
          format: uuid
        revision:
          type: integer
        presentationStatus:
          type: string
          enum:
            - OFFERED
            - DISPLAYED
            - ACKNOWLEDGED
            - STARTED
            - SUPERSEDED
        offeredAt:
          type: string
          format: date-time
        copyPayloadSchemaVersion:
          type: integer
        copyPayload:
          $ref: '#/components/schemas/TestLockedOutRenderPayload'
      required:
        - presentationId
        - lockoutId
        - launchAttemptId
        - revision
        - presentationStatus
        - offeredAt
        - copyPayloadSchemaVersion
        - copyPayload
    LockoutScopeType:
      type: string
      description: Lockout scope discriminator
      enum:
        - application
        - global
    LockoutStatus:
      type: string
      description: Lockout lifecycle state
      enum:
        - active
        - expired
        - revoked
    InSessionRenderPayload:
      type: object
      description: >-
        Fully resolved copy for the INSIGHT surface, frozen when the
        presentation was offered. Clients render these strings verbatim and
        never author copy.
      properties:
        schemaVersion:
          type: integer
        surfaceKind:
          type: string
          enum:
            - INSIGHT
        requestedLocale:
          type: string
        resolvedLocale:
          type: string
        messageVersion:
          type: integer
        insightName:
          type: string
        insightTimestampStart:
          type: string
          format: date-time
        insightTimestampEnd:
          type:
            - string
            - 'null'
          format: date-time
        warningNumber:
          type:
            - integer
            - 'null'
        numberWarnings:
          type:
            - integer
            - 'null'
        warningProgressSegments:
          type: array
          items:
            $ref: '#/components/schemas/WarningProgressSegment'
        insightFullText:
          type:
            - string
            - 'null'
        insightMessage:
          type: string
        insightCoaching:
          type: string
        title:
          type: string
        body:
          type:
            - string
            - 'null'
        bodyAddendum:
          type:
            - string
            - 'null'
        consequenceText:
          type:
            - string
            - 'null'
        contextLabel:
          type: string
        violationTimeLabel:
          type:
            - string
            - 'null'
        pillLabel:
          type: string
        ruleDisclosure:
          $ref: '#/components/schemas/RuleDisclosure'
        primaryAction:
          type: string
          enum:
            - ACKNOWLEDGE
        clientEffect:
          type: string
          enum:
            - NONE
            - RETURN_FULL_SCREEN_AFTER_ACTION
        primaryActionLabel:
          type: string
        acknowledgementConfirmationLabel:
          type: string
        remediationPreview:
          type: string
          enum:
            - NONE
            - LIVE_WEBCAM
        remediationPreviewAriaLabel:
          type:
            - string
            - 'null'
        remediationPreviewUnavailableText:
          type:
            - string
            - 'null'
        canDispute:
          type: boolean
        disputeActionLabel:
          type:
            - string
            - 'null'
        disputePlaceholder:
          type:
            - string
            - 'null'
        disputeRequiredText:
          type:
            - string
            - 'null'
        disputeMaxLength:
          type:
            - integer
            - 'null'
        disputeConfirmationLabel:
          type:
            - string
            - 'null'
        disputeOptions:
          type: array
          items:
            $ref: '#/components/schemas/DisputeOption'
        canSubmitFeedback:
          type: boolean
        thumbsDownAriaLabel:
          type:
            - string
            - 'null'
        thumbsUpAriaLabel:
          type:
            - string
            - 'null'
      required:
        - schemaVersion
        - surfaceKind
        - requestedLocale
        - resolvedLocale
        - messageVersion
        - insightName
        - insightTimestampStart
        - insightTimestampEnd
        - warningNumber
        - numberWarnings
        - warningProgressSegments
        - insightFullText
        - insightMessage
        - insightCoaching
        - title
        - body
        - bodyAddendum
        - consequenceText
        - contextLabel
        - violationTimeLabel
        - pillLabel
        - ruleDisclosure
        - primaryAction
        - clientEffect
        - primaryActionLabel
        - acknowledgementConfirmationLabel
        - remediationPreview
        - remediationPreviewAriaLabel
        - remediationPreviewUnavailableText
        - canDispute
        - disputeActionLabel
        - disputePlaceholder
        - disputeRequiredText
        - disputeMaxLength
        - disputeConfirmationLabel
        - disputeOptions
        - canSubmitFeedback
        - thumbsDownAriaLabel
        - thumbsUpAriaLabel
    TestSuspendedRenderPayload:
      type: object
      description: >-
        Resolved copy for the TEST_SUSPENDED surface. Platform owns every string
        here; the cooldown window is authoritative and a repeated presentation
        never moves it.
      properties:
        schemaVersion:
          type: integer
        surfaceKind:
          type: string
          enum:
            - TEST_SUSPENDED
        requestedLocale:
          type: string
        resolvedLocale:
          type: string
        messageVersion:
          type: integer
        testName:
          type: string
        suspendedAt:
          type: string
          format: date-time
        suspendedTimeLabel:
          type: string
        warningsUsed:
          type: integer
        warningsLimit:
          type: integer
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/WarningRecapItem'
        warningProgressSegments:
          type: array
          items:
            $ref: '#/components/schemas/WarningProgressSegment'
        primaryAction:
          type: string
          enum:
            - ACKNOWLEDGE_SUSPENSION
        cooldownDurationSeconds:
          type: integer
        cooldownStartsAt:
          type: string
          format: date-time
        cooldownExpiresAt:
          type: string
          format: date-time
        headerLabel:
          type: string
        headerSubline:
          type: string
        headerCountLabel:
          type: string
        title:
          type: string
        recapHeader:
          type: string
        cooldownLabel:
          type: string
        cooldownOverLabel:
          type: string
        primaryActionLabel:
          type: string
        cooldownOverActionLabel:
          type: string
        ariaLabel:
          type: string
        cooldownOverAriaLabel:
          type: string
      required:
        - schemaVersion
        - surfaceKind
        - requestedLocale
        - resolvedLocale
        - messageVersion
        - testName
        - suspendedAt
        - suspendedTimeLabel
        - warningsUsed
        - warningsLimit
        - warnings
        - warningProgressSegments
        - primaryAction
        - cooldownDurationSeconds
        - cooldownStartsAt
        - cooldownExpiresAt
        - headerLabel
        - headerSubline
        - headerCountLabel
        - title
        - recapHeader
        - cooldownLabel
        - cooldownOverLabel
        - primaryActionLabel
        - cooldownOverActionLabel
        - ariaLabel
        - cooldownOverAriaLabel
    TestLockedOutRenderPayload:
      type: object
      description: >-
        Resolved copy for the TEST_LOCKED_OUT surface, carrying both the
        counting-down and cooldown-over strings so the client needs no second
        lookup at expiry.
      properties:
        schemaVersion:
          type: integer
        surfaceKind:
          type: string
          enum:
            - TEST_LOCKED_OUT
        requestedLocale:
          type: string
        resolvedLocale:
          type: string
        messageVersion:
          type: integer
        testName:
          type: string
        warningsUsed:
          type: integer
        cooldownDurationSeconds:
          type: integer
        expiresAt:
          type: string
          format: date-time
        remainingSeconds:
          type: integer
        headerLabel:
          type: string
        headerSubline:
          type: string
        countdownLabel:
          type: string
        reasonHeading:
          type: string
        reasonBody:
          type: string
        primaryActionLabel:
          type: string
        readyLabel:
          type: string
        readySubline:
          type: string
        readyReasonBody:
          type: string
        readyActionLabel:
          type: string
        ariaLabel:
          type: string
        readyAriaLabel:
          type: string
      required:
        - schemaVersion
        - surfaceKind
        - requestedLocale
        - resolvedLocale
        - messageVersion
        - testName
        - warningsUsed
        - cooldownDurationSeconds
        - expiresAt
        - remainingSeconds
        - headerLabel
        - headerSubline
        - countdownLabel
        - reasonHeading
        - reasonBody
        - primaryActionLabel
        - readyLabel
        - readySubline
        - readyReasonBody
        - readyActionLabel
        - ariaLabel
        - readyAriaLabel
    WarningProgressSegment:
      type: object
      description: >-
        One segment of the warning strip. warningBudget is the terminal
        threshold: the strip carries warningBudget - 1 WARNING entries plus one
        TERMINAL (a single TERMINAL when the budget allows no nonterminal
        warning). WARNING ordinals are contiguous 1..n; TERMINAL ordinal is
        null.
      properties:
        ordinal:
          type:
            - integer
            - 'null'
          description: Positive for WARNING segments; null for TERMINAL.
        state:
          type: string
          enum:
            - PASSED
            - CURRENT
            - UPCOMING
        label:
          type: string
        ariaLabel:
          type: string
        kind:
          type: string
          enum:
            - WARNING
            - TERMINAL
      required:
        - ordinal
        - state
        - label
        - ariaLabel
        - kind
    RuleDisclosure:
      type: object
      description: Collapsed rule explanation rendered beneath the notification body.
      properties:
        collapsed:
          type: boolean
        heading:
          type: string
        body:
          type: string
        expandLabel:
          type: string
          description: Label shown when the disclosure is collapsed (invite to expand).
        collapseLabel:
          type: string
          description: Label shown when the disclosure is expanded (invite to collapse).
        toggleLabel:
          type: string
          description: Backward-compatible alias of expandLabel.
        collapsedAriaLabel:
          type: string
        expandedAriaLabel:
          type: string
      required:
        - collapsed
        - heading
        - body
        - expandLabel
        - collapseLabel
        - toggleLabel
        - collapsedAriaLabel
        - expandedAriaLabel
    DisputeOption:
      type: object
      description: >-
        One dispute choice frozen onto the presentation. The client may submit
        only an id listed here, and only with text the option permits.
      properties:
        id:
          type: string
        ordinal:
          type: integer
        label:
          type: string
        allowsText:
          type: boolean
        requiresText:
          type: boolean
        textLabel:
          type:
            - string
            - 'null'
        textPlaceholder:
          type:
            - string
            - 'null'
        textMaxLength:
          type:
            - integer
            - 'null'
      required:
        - id
        - ordinal
        - label
        - allowsText
        - requiresText
        - textLabel
        - textPlaceholder
        - textMaxLength
    WarningRecapItem:
      type: object
      description: One acknowledged warning replayed on the suspension recap.
      properties:
        ordinal:
          type: integer
        insightName:
          type: string
        acknowledgedAt:
          type: string
          format: date-time
        acknowledgedTimeLabel:
          type: string
      required:
        - ordinal
        - insightName
        - acknowledgedAt
        - acknowledgedTimeLabel
  securitySchemes:
    CognitoUserPoolAuthorizer:
      type: oauth2
      description: >-
        OAuth 2.0 client credentials flow. Contact timeback@trilogy.com to
        request credentials for your application.
      flows:
        clientCredentials:
          tokenUrl: https://platform.dev.timeback.com/auth/1.0/token
          scopes:
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster.readonly: roster readonly
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster-core.readonly: roster-core readonly
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster.createput: roster createput
            https://purl.imsglobal.org/spec/lti/v1p3/scope/lti.readonly: lti readonly
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster-demographics.readonly: roster-demographics readonly
            https://timeback-platform.trilogy.com/consent/scope/consent.write: consent write
            https://timeback-platform.trilogy.com/consent/scope/consent.read: consent read
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster-core.createput: roster-core createput
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster.delete: roster delete
            https://purl.imsglobal.org/spec/or/v1p2/scope/roster-core.delete: roster-core delete
            https://purl.imsglobal.org/spec/case/v1p0/scope/case.readonly: case readonly
            https://purl.imsglobal.org/spec/case/v1p0/scope/case.createput: case createput
            https://purl.imsglobal.org/spec/case/v1p0/scope/case.delete: case delete
            https://timeback-platform.trilogy.com/competency-track/scope/competency-track.readonly: competency-track readonly
            https://timeback-platform.trilogy.com/competency-track/scope/competency-track.write: competency-track write
            https://timeback-platform.trilogy.com/competency-track/scope/competency-track.delete: competency-track delete
            https://timeback-platform.trilogy.com/content/scope/content.write: content write
            https://timeback-platform.trilogy.com/content/scope/content.read: content read
            https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.write: events write
            https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.readonly: events readonly
            https://timeback-platform.trilogy.com/webhooks/scope/webhooks.write: webhooks write
            https://timeback-platform.trilogy.com/webhooks/scope/webhooks.read: webhooks read
            https://timeback-platform.trilogy.com/webhooks/scope/webhooks.delete: webhooks delete

````