DEV Community

Cover image for Stop Calling It a Transcription Test Until You Save the Test Manifest
Lemarie Eaglen
Lemarie Eaglen

Posted on

Stop Calling It a Transcription Test Until You Save the Test Manifest

A speech-to-text comparison is not reproducible if the only surviving evidence is a screenshot and a percentage. The result may depend on the exact MP3, the selected language, the model mode, the account tier, and whether someone corrected the export before scoring it.

I ran this workflow audit on November 5, 2026 in the Asia/Shanghai timezone. The test material for the code below is one synthetic manifest entry describing a 42.8-second, single-speaker English MP3 at 128 kbps and 44.1 kHz. No private recording is included, and the example does not claim a product accuracy score.

The goal is smaller and more useful: reject incomplete test records before they enter a benchmark repository.

What a useful test record must preserve

At minimum, save the test date, material source, duration, codec, bitrate, sample rate, speaker count, language, file hash, tool settings, and raw export name. These fields answer the questions that appear after a surprising result.

Was the “bad” transcript produced from a low-bitrate copy? Did the reviewer leave language detection on for accented speech? Was speaker separation enabled for a single speaker? Did two files with the same friendly name contain different bytes?

A SHA-256 digest is especially helpful. It identifies the exact input without publishing the recording. The digest does not prove consent or ownership, so the manifest still needs a human-readable material field.

A small validator in standard Python

The following script reads JSON Lines. It checks for required fields, an ISO-formatted timestamp, positive numeric values, and a 64-character lowercase SHA-256 digest.

from __future__ import annotations

import argparse
import json
import re
from datetime import datetime
from pathlib import Path


REQUIRED = {
    "id",
    "tested_at",
    "material",
    "duration_seconds",
    "codec",
    "bitrate_kbps",
    "sample_rate_hz",
    "speakers",
    "language",
    "sha256",
    "mode",
    "raw_export",
}


def validate(case: dict[str, object]) -> list[str]:
    errors: list[str] = []
    missing = sorted(REQUIRED - case.keys())
    if missing:
        errors.append("missing:" + ",".join(missing))

    try:
        datetime.fromisoformat(str(case.get("tested_at", "")))
    except ValueError:
        errors.append("invalid:tested_at")

    for field in ("duration_seconds", "bitrate_kbps", "sample_rate_hz", "speakers"):
        value = case.get(field)
        if not isinstance(value, (int, float)) or value <= 0:
            errors.append(f"invalid:{field}")

    digest = str(case.get("sha256", ""))
    if not re.fullmatch(r"[0-9a-f]{64}", digest):
        errors.append("invalid:sha256")
    return errors


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("manifest", type=Path)
    args = parser.parse_args()

    failed = 0
    for number, line in enumerate(args.manifest.read_text(encoding="utf-8").splitlines(), 1):
        case = json.loads(line)
        errors = validate(case)
        status = "PASS" if not errors else "FAIL " + " ".join(errors)
        failed += bool(errors)
        print(f"line={number} id={case.get('id', 'unknown')} {status}")
    return 1 if failed else 0


if __name__ == "__main__":
    raise SystemExit(main())
Enter fullscreen mode Exit fullscreen mode

Save one test case in audit_manifest.jsonl:

{"id":"meeting-clean-01","tested_at":"2026-11-05T10:30:00+08:00","material":"consented internal script","duration_seconds":42.8,"codec":"mp3","bitrate_kbps":128,"sample_rate_hz":44100,"speakers":1,"language":"en-US","sha256":"4f42c1a3d11846667da9ea25ef83893395d60e1dd7e27c6b1f3a256f569b9c42","mode":"basic, language=en-US, speaker separation=off","raw_export":"meeting-clean-01.txt"}
Enter fullscreen mode Exit fullscreen mode

Run it with python3 audit_manifest.py audit_manifest.jsonl. The verified output is:

line=1 id=meeting-clean-01 PASS
Enter fullscreen mode Exit fullscreen mode

The validator deliberately says nothing about transcription accuracy. It proves that a reviewer saved enough context to interpret the later score.

Add the transcript without destroying the raw evidence

Keep three separate artifacts for each case: the human-reviewed reference, the untouched service export, and any corrected transcript. Never overwrite the raw output while fixing names or punctuation.

This separation supports two useful measurements. Raw word error rate estimates recognition performance under the recorded settings. Assisted editing time measures how much human work is required to reach a publishable transcript.

Both can matter. A transcript with one incorrect customer name may have a low error rate but still be risky to publish. Add critical-term checks for names, dates, prices, product terms, or medical vocabulary when the use case demands them.

A dated audit of the browser workflow

On November 5, 2026, I reviewed the public Audio Converter AI MP3 page rather than treating its marketing text as test evidence. The interface exposed local upload and compatible public-link input, Basic and Advanced modes, source-language selection with automatic detection, and a speaker-separation option.

The page also described editable transcripts, several export formats, summaries, and mind maps. Its upload panel showed different file limits for Standard and Advanced processing, with plan-dependent restrictions. Those observations document available controls on that date. They do not prove speed or accuracy.

If you use a browser-based MP3 to text converter, copy the selected mode and language into the manifest before processing. Record whether speaker separation was enabled and keep the raw exported file. If the interface changes later, the test date explains why your settings differ from someone else’s reproduction.

Turn the manifest into a CI gate

The script returns a nonzero exit code when any line fails. That makes it suitable for a small continuous-integration check before benchmark results are merged.

A practical repository can require one manifest line per audio file, verify that referenced exports exist, and reject reused IDs. It can also calculate the real SHA-256 digest from an approved local corpus and compare it with the recorded value.

Do not upload sensitive recordings to CI simply to prove that the hash matches. Keep restricted media in an access-controlled location and publish only metadata when consent or licensing does not allow redistribution.

Test more than clean narration

One polished sample is a demo, not a benchmark. Build a compact matrix that reflects the intended workload:

  • Clean, single-speaker speech
  • The same script at lower volume
  • Documented background noise
  • Two speakers with short overlaps
  • Proper names and domain terms
  • A long pause or interrupted connection
  • Relevant accents and languages

Change one condition at a time when possible. If the words, microphone, speaker, and noise all change together, the result cannot isolate a cause.

Record latency consistently too. Decide whether timing starts at upload, submission, or processing. A hosted service can change after deployment, so repeat time-sensitive tests and keep the date beside every result.

Add an error taxonomy before reviewing the outputs. I use separate labels for ordinary vocabulary, critical terms, punctuation, speaker attribution, timestamps, and formatting. The categories prevent a polished paragraph from hiding a serious identity error. They also make follow-up work concrete. A team can decide that punctuation is acceptable after light editing while speaker-attribution failures require manual review. Store the taxonomy version in the repository so changing a label definition does not silently rewrite the meaning of older scores.

The review becomes useful when someone else can challenge it

The strongest part of a transcription test is not the winning percentage. It is the evidence that lets another person reproduce the conditions, inspect the raw output, and disagree with the scoring policy.

Start with the manifest before opening the MP3 to text converter. Preserve the exact input identity and untouched export. Then score accuracy, critical terms, speaker labels, timestamps, and editing effort as separate properties.

That workflow will not produce one universal winner. It will produce a comparison that survives more than one screenshot.

Top comments (0)