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

# Quality Signals

> Two independent checks that tell you which lines to look at before you publish

Every job can return two blocks of evidence alongside its results: what a second,
independent listener made of the transcript, and how the timings were produced.

Neither changes the output. They tell you **where to look** if you want to check
something before it goes live — which matters most on the API, where no one from
your team sees the lyrics unless you route them somewhere yourself.

Both appear on `GET /api/v1/jobs/{job_id}` and in the `job.complete` and
`job.awaiting_review` webhook payloads.

## null means "not checked", not "nothing found"

This is the one thing to get right.

| Value                   | Meaning                            |
| ----------------------- | ---------------------------------- |
| `null`                  | The check did not run              |
| `{ "suggestions": [] }` | It ran, and agreed with every line |

An empty `suggestions` array is the **strongest positive signal** the pipeline
produces — an independent listener heard the same words we transcribed. `null`
tells you nothing at all about the lyrics.

<Warning>
  Do not write `if (!job.second_opinion)` and treat both cases the same. That
  reads "we never checked" as "the transcript is clean", which is the opposite of
  what it means. Test for `null` explicitly.
</Warning>

Both blocks are `null` when the feature is not enabled for your account, and
`second_opinion` is additionally `null` for languages the second listener does
not cover, and on jobs created before this feature existed.

## second\_opinion

A second speech engine listens to the song independently and its transcript is
compared against ours, line by line. It does not see our lyrics first, so where
the two agree, two systems reached the same words separately.

```json theme={null}
{
  "second_opinion": {
    "total_lines": 59,
    "agreed_lines": 47,
    "match_ratio": 0.79,
    "suggestions": [
      {
        "kind": "line",
        "current": "तेरे नैना",
        "heard": "तेरी नैना",
        "occurrences": [
          { "line_index": 12, "at_seconds": 48 },
          { "line_index": 30, "at_seconds": 121 }
        ]
      },
      {
        "kind": "section",
        "current": null,
        "heard": "हा हा हा",
        "occurrences": [{ "line_index": 25, "at_seconds": 96 }]
      }
    ],
    "hidden_count": 0
  }
}
```

| Field          | Type   | Notes                                                                     |
| -------------- | ------ | ------------------------------------------------------------------------- |
| `total_lines`  | number | Lines in the transcript                                                   |
| `agreed_lines` | number | Lines no suggestion touches                                               |
| `match_ratio`  | number | Share of transcript words the listener also heard, `0`–`1`                |
| `suggestions`  | array  | Disagreements worth a look. Empty means full agreement.                   |
| `hidden_count` | number | Found but not returned. Non-zero means `suggestions` is not the full set. |

### The two kinds are not equally important

<Note>
  **`section` findings deserve more of your attention than `line` findings.**
  A `line` finding is usually a spelling or vowel-length difference. A `section`
  finding means the listener heard singing where our transcript has nothing —
  which can mean a whole verse or chorus is missing.
</Note>

| `kind`    | What it means                                                                                                                | `current`        |
| --------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `line`    | This line was heard differently. Both `current` and `heard` are whole lines, so acting on it is a straight line replacement. | the current line |
| `section` | Words were heard where the transcript has none — possibly missing lyrics.                                                    | `null`           |

`occurrences` lists every place the same change applies. `at_seconds` is
approximate — accurate enough to seek a player to the right part of the song, not
a timestamp for publishing. Use the LRC or word-level downloads for that.

### Expect disagreements on clean transcripts

Sung material produces genuine disagreement between any two engines: held vowels,
ad-libs, backing vocals, and compound words that one system splits and the other
joins. A handful of `line` suggestions on a correct transcript is normal and does
not mean the lyrics are wrong.

The check is deliberately tuned to over-report rather than under-report, because a
missed verse is expensive and a spurious spelling suggestion is not.

## alignment

How the timings on this job were produced, and which lines look suspect.

```json theme={null}
{
  "alignment": {
    "method": "forced",
    "coverage": 0.998,
    "line_flags": [
      { "line_index": 25, "text": "साथ चलेंगे हम", "ratio": 4.1 }
    ]
  }
}
```

| `method`          | Meaning                                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `forced`          | Timings came from direct audio-to-text alignment. The most accurate method available.                                                    |
| `forced_rejected` | Forced alignment ran but its result failed our quality gate, so model-generated timings were delivered instead. Worth checking this job. |
| `model`           | Model-generated timings. Forced alignment was not attempted for this job.                                                                |

`coverage` is the share of the transcript that received a timing, and is `null`
unless forced alignment produced the result.

### line\_flags

Lines whose audio matches their text far worse than the other lines in the same
song. In practice this is a short list — often empty — and each entry is worth
thirty seconds of listening.

| Field        | Notes                                                                                                     |
| ------------ | --------------------------------------------------------------------------------------------------------- |
| `line_index` | Zero-based index into the transcript                                                                      |
| `text`       | The line as transcribed                                                                                   |
| `ratio`      | How many times worse this line scores than similar-length lines in the same song. Higher is more suspect. |

<Note>
  **What this catches:** a line placed where its words are not sung. Forced
  alignment must place every line it is given, so a long instrumental break can
  pull the following line in early. It also catches transcription errors large
  enough to matter against the line's length.

  **What it does not catch:** a wrong word that still sounds close to what was
  sung. An empty `line_flags` is not a guarantee of correctness — it means
  nothing stood out against the rest of this song.
</Note>

## A reasonable way to use these

<Steps>
  <Step title="Treat section findings as blocking">
    Any `kind: "section"` finding is worth a human listen before publishing. This
    is the case where lyrics may simply be absent.
  </Step>

  <Step title="Check every flagged line">
    `line_flags` is short by design. Seek to the line and listen.
  </Step>

  <Step title="Watch for forced_rejected">
    It means this specific job fell back to a less accurate timing method.
  </Step>

  <Step title="Let line findings inform, not block">
    A few `kind: "line"` suggestions are normal on correct transcripts.
  </Step>
</Steps>

## Availability

Both are enabled per account and are off by default. Contact us if you would like
either turned on — the second listener adds a small per-song cost, forced
alignment does not.

When neither is enabled, both fields are present and `null` on every response, so
you can write your integration against them before they are switched on.
