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

# DecisionScorecardAPI mirrors erdo_decision_scorecard: raw aggregates with their


> denominators, stratified by decision class and evidence kind, with no eligibility verdict and no pooled outcome rate.




## OpenAPI

````yaml /api/openapi.json get /v1/decisions-scorecard
openapi: 3.0.0
info:
  title: Erdo API
  description: >-
    Erdo's REST API: query and write datasets, run agents, manage threads,
    integrations, pages, evals, workstreams, and experiments. Authenticate with
    a Bearer API key (erdo_api_...) or scoped token (erdo_token_...).
  version: '2026-08-07'
servers:
  - url: https://api.erdo.ai
    description: Production
security:
  - bearerAuth: []
paths:
  /v1/decisions-scorecard:
    get:
      summary: >
        DecisionScorecardAPI mirrors erdo_decision_scorecard: raw aggregates
        with their
      description: >
        denominators, stratified by decision class and evidence kind, with no
        eligibility verdict and no pooled outcome rate.
      operationId: GET:mcp.DecisionScorecardAPI
      parameters:
        - allowEmptyValue: true
          explode: true
          in: query
          name: workstream_slug
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          explode: true
          in: query
          name: source
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          explode: true
          in: query
          name: decision_class
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          explode: true
          in: query
          name: since
          required: false
          schema:
            type: string
          style: form
        - allowEmptyValue: true
          explode: true
          in: query
          name: until
          required: false
          schema:
            type: string
          style: form
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  decide_latency:
                    $ref: '#/components/schemas/types.DecisionDecideLatency'
                  deciders:
                    $ref: '#/components/schemas/types.DecisionDeciderBreakdown'
                  execution:
                    $ref: '#/components/schemas/types.DecisionExecutionCoverage'
                  measurement:
                    $ref: '#/components/schemas/types.DecisionMeasurementCoverage'
                  outcomes_by_class_and_evidence:
                    description: >
                      deterministic postcondition and an observational
                      before/after are not comparable evidence, and one campaign
                      class's results say nothing about another's.
                    items:
                      $ref: '#/components/schemas/types.DecisionOutcomeStratum'
                    title: >
                      OutcomesByClassAndEvidence is the outcome split,
                      stratified. Never pooled: a
                    type: array
                  outcomes_by_source_and_evidence:
                    description: >
                      family that recorded them — the actor/policy regime axis.
                      A record where the engine gate's decisions settle
                      differently from a human's is a fact the class cut cannot
                      show.
                    items:
                      $ref: '#/components/schemas/types.DecisionOutcomeStratum'
                    title: >
                      OutcomesBySourceAndEvidence cuts the same settled effects
                      by the producer
                    type: array
                  totals:
                    $ref: '#/components/schemas/types.DecisionTotals'
                  window:
                    $ref: '#/components/schemas/types.DecisionScorecardWindow'
                type: object
          description: Success response
        default:
          $ref: '#/components/responses/APIError'
components:
  schemas:
    types.DecisionDecideLatency:
      description: |
        being authorized, in seconds.
      properties:
        decided:
          description: |
            reach authorized\_at — so this describes the time to a yes.
          format: int64
          title: >
            Decided is how many decisions contributed. Rejections are absent —
            they never
          type: integer
        p50_seconds:
          type: number
        p90_seconds:
          type: number
      title: >
        DecisionDecideLatency is how long decisions waited between being
        proposed and
      type: object
    types.DecisionDeciderBreakdown:
      properties:
        answered:
          description: >
            proposal nobody has answered has no decider yet, so including it
            would deflate every rate below by however long the queue happens to
            be.
          format: int64
          title: >
            Answered is the denominator: decisions that reached a decider at
            all. A
          type: integer
        by_decider_kind:
          additionalProperties:
            format: int64
            type: integer
          title: >
            ByDeciderKind: human, llm_agent, deterministic_policy, safe_default,
            system.
          type: object
        human_override:
          description: >
            rejected, decided by a person. It is the disagreement rate, and it
            is reported beside its denominator rather than as a bare percentage
            because ten refusals out of twelve and ten out of a thousand are
            opposite findings.
          format: int64
          title: >
            HumanOverride is a human refusing something the system proposed —
            status
          type: integer
        human_override_rate:
          type: number
        safe_default:
          description: >
            the clearest signal in this whole readout that a queue is being
            ignored rather than governed.
          format: int64
          title: >
            SafeDefault is how often nobody answered and the safe default
            applied. It is
          type: integer
        safe_default_rate:
          type: number
      type: object
    types.DecisionExecutionCoverage:
      properties:
        actions:
          format: int64
          type: integer
        by_status:
          additionalProperties:
            format: int64
            type: integer
          title: |
            ByStatus counts every action by its single attempt's outcome.
          type: object
        decisions_with_actions:
          description: >
            all. The rest are real decisions with nothing to execute — a
            strategy commitment, an experiment settlement — and counting them as
            unexecuted would invent a failure.
          format: int64
          title: >
            DecisionsWithActions is how many decisions authorized an external
            call at
          type: integer
        decisions_without_actions:
          format: int64
          type: integer
        unknown:
          description: >
            whether the rest of this section can be trusted: an action nothing
            confirmed may or may not be live, and a record with many of them is
            one whose execution truth is partly unknown.
          format: int64
          title: >
            Unknown is called out separately because it is the number that
            decides
          type: integer
      type: object
    types.DecisionMeasurementCoverage:
      properties:
        by_measurability:
          additionalProperties:
            format: int64
            type: integer
          description: >
            that never will: measurable, unmeasurable,
            unmeasurable\_invalid\_contract.
          title: >
            ByMeasurability separates the declarations that can be scored from
            the ones
          type: object
        by_status:
          additionalProperties:
            format: int64
            type: integer
          title: >
            ByStatus is where every effect currently sits, including the parked
            ones.
          type: object
        censored:
          format: int64
          type: integer
        decisions_with_declared_effect:
          description: >
            expected to change. The complement is not a failure — most decisions
            have no business effect anything could measure — but it bounds
            everything the outcome strata can claim about the record as a whole.
          format: int64
          title: >
            DecisionsWithDeclaredEffect is how many decisions said in advance
            what they
          type: integer
        decisions_without_declared_effect:
          format: int64
          type: integer
        effects:
          format: int64
          type: integer
        measurement_unavailable:
          format: int64
          type: integer
        settled:
          description: >
            numbers a reader needs to size the outcome split honestly: what
            produced an answer, what was overtaken before it could, and what is
            waiting on a reader that does not exist yet. The size of Unavailable
            is what will justify building the synced-dataset measurement runner.
          format: int64
          title: >
            Settled, Censored and Unavailable are pulled out because they are
            the three
          type: integer
      type: object
    types.DecisionOutcomeStratum:
      description: >
        stratum names the evidence kind that settled it, because the same counts
        mean different things under different evidence and the label is what
        stops a reader carrying the stronger claim across.
      properties:
        decision_class:
          description: |
            other is empty.
          title: >
            DecisionClass or Source, depending on which cut this stratum belongs
            to; the
          type: string
        evidence_kind:
          type: string
        inconclusive:
          format: int64
          type: integer
        met:
          format: int64
          type: integer
        met_label:
          description: >
            SAY about those two counts — "confirmed"/"not confirmed" for
            deterministic, "worked"/"did not work" only for experimental, "moved
            as expected"/"did not move as expected" for observational. They ride
            on the stratum so no consumer has to re-derive the vocabulary, and
            so a surface that ignores the evidence kind is visibly ignoring it.
          title: >
            MetLabel and NotMetLabel are what this stratum's evidence entitles a
            reader to
          type: string
        not_met:
          format: int64
          type: integer
        not_met_label:
          type: string
        settled:
          format: int64
          title: |
            Settled is this stratum's denominator: Met + NotMet + Inconclusive.
          type: integer
        source:
          type: string
      title: |
        DecisionOutcomeStratum is one comparable group of SETTLED effects. Every
      type: object
    types.DecisionTotals:
      properties:
        by_source:
          additionalProperties:
            format: int64
            type: integer
          type: object
        by_status:
          additionalProperties:
            format: int64
            type: integer
          description: |
            than any single number derived from it.
          title: >
            ByStatus and BySource are counts, not rates — a status distribution
            says more
          type: object
        decisions:
          description: |
            here is a share of.
          format: int64
          title: >
            Decisions is every decision in the window, the denominator
            everything else
          type: integer
        legacy_unclassified:
          description: >
            is inside Decisions and excluded from every outcome stratum, and it
            is named here so the two numbers can be reconciled rather than
            leaving a reader to wonder where the difference went.
          format: int64
          title: >
            LegacyUnclassified is the backfilled history that predates intent
            capture. It
          type: integer
      type: object
    types.DecisionScorecardWindow:
      properties:
        since:
          format: date-time
          type: string
        until:
          format: date-time
          type: string
      type: object
  responses:
    APIError:
      content:
        application/json:
          schema:
            externalDocs:
              url: https://pkg.go.dev/encore.dev/beta/errs#Error
            properties:
              code:
                description: Error code
                example: not_found
                externalDocs:
                  url: https://pkg.go.dev/encore.dev/beta/errs#ErrCode
                type: string
              details:
                description: Error details
                type: object
              message:
                description: Error message
                type: string
            title: APIError
            type: object
      description: Error response
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An Erdo API key (erdo_api_...) or scoped token (erdo_token_...).

````