## Ask what to do with a Q&A entry

**post** `/v2/training_data/oracle`

Checks a proposed Q&A without writing. Optional externalId or an existing normalized question addresses a target. Changed content is compared with that entry even if retrieval or excludeIds misses it. The judge continues past agreement to detect later contradictions; uncertainty takes precedence over agreement. Another agreeing Q&A remains visible for duplicate review.

Actions: create means no overlap found in checked candidates; update_target refers to existing; update_qna refers to target; review_qna / review_article / review_file require review of the source; skip means an identical payload or already-covered answer. existing and Q&A candidates include revisions: use PATCH expectedRevision for a subsequent reviewed update.

The evidence is bounded: retrieval can miss knowledge, document excerpts omit context, and checks observe changing data. checkTruncated reports verification shortlist or text limits and yields unclear unless a contradiction was found. False does not imply exhaustive coverage or factual correctness. Inspect full sources before promotion. Dependencies failing returns 503; this endpoint never writes.

### Header Parameters

- `"Featurebase-Version": optional "2026-08-19.orbit" or "2026-01-01.nova" or "2025-12-12.clover"`

  - `"2026-08-19.orbit"`

  - `"2026-01-01.nova"`

  - `"2025-12-12.clover"`

### Body Parameters

- `answer: string`

  The answer the entry would give. Compared by the judge, never used as a search query.

- `questions: array of string`

  Question variants this answer applies to (1–50). Phrase them the way customers ask.

- `answerFormat: optional "markdown" or "html"`

  Format of `answer`. `markdown` (default) is stored as-is; `html` is converted to markdown.

  - `"markdown"`

  - `"html"`

- `excludeIds: optional array of string`

  Q&A entry / training file IDs to omit from retrieval. The addressed Q&A entry is still compared when its content changes.

- `externalId: optional string`

  Stable identity of the would-be Q&A entry. The oracle only reads; it never creates or updates it.

- `title: optional string`

  Short label for the would-be entry (also used as a search query)

### Returns

- `Oracle object { action, candidates, checkTruncated, 7 more }`

  - `action: "create" or "update_target" or "update_qna" or 4 more`

    Suggested next step. `create`: no overlap found in the checked candidates; verify the source before writing. `update_target`: an entry already carries one of these questions (`existing`) and should be updated with this content — use PATCH with expectedRevision from existing to bind the write to this check. `update_qna`: an existing Q&A entry already answers this with the same facts — merge into it (`target`) instead of adding a second one. `review_qna` / `review_article` / `review_file`: an existing item (`target`) contradicts this answer or the judge could not decide — a human should pick the right fact and fix the source. `skip`: the knowledge already exists (an article or file answers it, or the payload is identical to the entry that already carries the question); nothing to write.

    - `"create"`

    - `"update_target"`

    - `"update_qna"`

    - `"review_qna"`

    - `"review_article"`

    - `"review_file"`

    - `"skip"`

  - `candidates: array of KnowledgeMatchCandidate`

    Retrieved items and the addressed entry (first when present), at most 10. Excerpts are partial evidence.

    - `id: string`

      ID of the existing item

    - `externalId: string`

      The item's source identity, for training files and Q&A

    - `kind: "qna" or "training_file" or "help_center_article"`

      What kind of knowledge item matched: a Q&A entry, a training file / crawled page, or a live help-center article.

      - `"qna"`

      - `"training_file"`

      - `"help_center_article"`

    - `questions: array of string`

      Question variants, for Q&A entries

    - `revision: number`

      Q&A revision compared by the judge; null for other kinds. Use with PATCH expectedRevision.

    - `section: string`

      Heading breadcrumb of the matching section, for training files

    - `similarity: number`

      Cosine similarity between the query and item. Calibrate any threshold using representative examples; it is not a correctness or contradiction score. `null` when the item was found by keywords only. Arrays are already ordered closest first.

    - `source: string`

      The item's `source` label, for Q&A entries and training files

    - `text: string`

      Excerpt of the existing content the judge compared against (Q&A answer, matching document section, or article body), up to 1200 characters plus an ellipsis when cut.

    - `title: string`

      Title of the existing item

    - `url: string`

      Public URL of the item when it has one

  - `checkTruncated: boolean`

    A candidate or text budget limited verification (including clipped proposed answers or Q&A answers). This yields unclear unless a contradiction was already found. False does not mean the entire workspace was exhaustively checked.

  - `existing: object { id, question, revision }`

    The Q&A entry addressed by externalId or a normalized question, including its checked revision, or null

    - `id: string`

      Q&A entry ID

    - `question: string`

      Matching question from your request, or its first question when addressed by externalId

    - `revision: number`

      Revision of the addressed entry at check time. Use with PATCH expectedRevision.

  - `judged: array of object { candidateId, kind, reason, verdict }`

    Per-candidate judge verdicts, in the order they were judged. Judging continues after agreement or uncertainty and stops on a contradiction. The addressed entry is always compared when its content changes. Only shortlisted candidates are judged, so this is usually shorter than `candidates`.

    - `candidateId: string`

      ID of the judged candidate

    - `kind: "qna" or "training_file" or "help_center_article"`

      What kind of knowledge item matched: a Q&A entry, a training file / crawled page, or a live help-center article.

      - `"qna"`

      - `"training_file"`

      - `"help_center_article"`

    - `reason: string`

      The judge's one-line explanation

    - `verdict: "same_topic" or "contradicts" or "different" or "unclear"`

      The judge's verdict for this candidate

      - `"same_topic"`

      - `"contradicts"`

      - `"different"`

      - `"unclear"`

  - `object: "oracle"`

    Object type identifier

    - `"oracle"`

  - `reason: string`

    One or two sentences explaining the action, from the judge when it ran

  - `target: KnowledgeMatchCandidate`

    The existing item the action refers to, with its excerpt; `null` for `create` / `update_target`. For a `different` verdict the closest miss is `candidates[0]`.

  - `timings: object { judgeCalls, judgeMs, retrievalMs }`

    Where the time went

    - `judgeCalls: number`

      Number of judge calls made

    - `judgeMs: number`

      Time spent in the judge

    - `retrievalMs: number`

      Time spent searching

  - `verdict: "same_topic" or "contradicts" or "different" or 2 more`

    How the closest existing item relates to the entry. `same_topic`: it answers the same customer question (the entry would be a duplicate, rewording, or updated version). `contradicts`: same question, incompatible facts. `different`: a different question, even if the wording overlaps. `unclear`: the judge could not decide. `no_match`: nothing similar was found.

    - `"same_topic"`

    - `"contradicts"`

    - `"different"`

    - `"unclear"`

    - `"no_match"`

### Example

```http
curl https://do.featurebase.app/v2/training_data/oracle \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $FEATUREBASE_API_KEY" \
    -d '{
          "answer": "You can request a refund within 30 days from **Settings → Billing**.",
          "questions": [
            "How do I request a refund?",
            "Can I get my money back?"
          ],
          "answerFormat": "markdown",
          "excludeIds": [
            "67ec1234abcd5678ef901235"
          ],
          "title": "Refund requests"
        }'
```

#### Response

```json
{
  "action": "review_article",
  "candidates": [
    {
      "id": "67ec1234abcd5678ef901236",
      "externalId": null,
      "kind": "qna",
      "questions": [
        "How do I request a refund?"
      ],
      "revision": 1,
      "section": null,
      "similarity": 0.61,
      "source": null,
      "text": "You can request a refund within 30 days from **Settings → Billing**.",
      "title": "Refund requests",
      "url": null
    }
  ],
  "checkTruncated": true,
  "existing": {
    "id": "67ec1234abcd5678ef901234",
    "question": "How long do refunds take?",
    "revision": 1
  },
  "judged": [
    {
      "candidateId": "67ec1234abcd5678ef901236",
      "kind": "qna",
      "reason": "Both answer how to request a refund.",
      "verdict": "same_topic"
    }
  ],
  "object": "oracle",
  "reason": "The new entry says 14 days; the article says 30 days.",
  "target": {
    "id": "67ec1234abcd5678ef901236",
    "externalId": null,
    "kind": "qna",
    "questions": [
      "How do I request a refund?"
    ],
    "revision": 1,
    "section": null,
    "similarity": 0.61,
    "source": null,
    "text": "You can request a refund within 30 days from **Settings → Billing**.",
    "title": "Refund requests",
    "url": null
  },
  "timings": {
    "judgeCalls": 1,
    "judgeMs": 610,
    "retrievalMs": 420
  },
  "verdict": "same_topic"
}
```
