Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,24 @@ jobs:

- name: Run mypy
run: uv run mypy src/ --ignore-missing-imports

schemas:
name: Schema Drift Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'

- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0

- name: Install dependencies
run: uv sync --extra dev

- name: Check committed schemas match Pydantic models
run: make check-schemas
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ jobs:
- name: Create Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
files: dist/*
files: |
dist/*
docs/schemas/*.json
draft: false
prerelease: false
generate_release_notes: true
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.2] - 2026-05-22

### Changed

- Word-level `speaker` in combined transcripts now falls back to the enclosing segment's speaker when WhisperX's word-level diarization join doesn't intersect any pyannote span (typically a boundary-overlap gap on short, low-confidence trailing words). Previously such words were emitted with `speaker: null` despite the segment carrying a confident label. The Pydantic contract is unchanged — word-level `speaker` is still nullable in principle — but in practice the field is now populated whenever the segment-level assignment is confident.

### Added

- Published JSON Schemas for the combined transcript and batch summary documents under `docs/schemas/` (`combined-transcript-v1.json`, `batch-summary-v1.json`). They are generated from the Pydantic source-of-truth in serialization mode, attached as GitHub release assets, and kept in lockstep with the models by a CI drift check. Consumers without access to the Python package can now fetch the schema for a pinned AR version directly from the release tag and validate transcripts against it. See `docs/service.md` for the consumption pattern.
- `make generate-schemas` and `make check-schemas` Makefile targets. The drift check now runs as part of `make all-checks` and as a dedicated CI job (`Schema Drift Check` in `ci.yml`).

### Documentation

- Refreshed the README banner image.

## [0.2.1] - 2026-05-21

### Fixed
Expand Down
16 changes: 14 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help install install-dev install-whisperx test test-verbose test-integration test-coverage lint lint-fix format format-check type-check clean pre-commit pre-commit-install all-checks ci dev-setup stats build-image run-service-local
.PHONY: help install install-dev install-whisperx test test-verbose test-integration test-coverage lint lint-fix format format-check type-check clean pre-commit pre-commit-install all-checks ci dev-setup stats build-image run-service-local generate-schemas check-schemas

# Read the version from pyproject.toml so build-image stays in sync with releases.
VERSION := $(shell awk -F'"' '/^version = /{print $$2; exit}' pyproject.toml)
Expand Down Expand Up @@ -65,7 +65,19 @@ clean: ## Remove generated files and caches
find . -type d -name __pycache__ -exec rm -rf {} +
find . -type f -name '*.pyc' -delete

all-checks: lint type-check test ## Run all checks (lint, type-check, test)
generate-schemas: ## Regenerate docs/schemas/*.json from the Pydantic models
uv run python scripts/generate_schemas.py

check-schemas: ## Fail if docs/schemas/*.json is out of sync with the Pydantic models
@uv run python scripts/generate_schemas.py >/dev/null
@if [ -n "$$(git status --porcelain docs/schemas/)" ]; then \
echo ""; \
echo "docs/schemas/ is out of sync — run 'make generate-schemas' and commit."; \
git status --short docs/schemas/; \
exit 1; \
fi

all-checks: lint type-check test check-schemas ## Run all checks (lint, type-check, test, schema drift)
@echo ""
@echo "All checks passed!"

Expand Down
Binary file modified docs/images/audio-refinery-banner.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
192 changes: 192 additions & 0 deletions docs/schemas/batch-summary-v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
{
"$defs": {
"BatchTotals": {
"description": "Per-batch aggregate counts. Always sums to ``submitted``.",
"properties": {
"completed": {
"minimum": 0,
"title": "Completed",
"type": "integer"
},
"failed": {
"minimum": 0,
"title": "Failed",
"type": "integer"
},
"submitted": {
"minimum": 0,
"title": "Submitted",
"type": "integer"
}
},
"required": [
"submitted",
"completed",
"failed"
],
"title": "BatchTotals",
"type": "object"
},
"JobSummaryEntry": {
"description": "One per-job record inside a ``BatchSummary``.\n\nThe ``status`` field discriminates between success and failure shapes.\nOn ``completed``, ``completed_at`` and ``duration_seconds`` are populated\nand ``failed_at``/``stage``/``error``/``retryable`` are None. On ``failed``,\nthe reverse holds.",
"properties": {
"completed_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Completed At"
},
"duration_seconds": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"title": "Duration Seconds"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Error"
},
"failed_at": {
"anyOf": [
{
"format": "date-time",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Failed At"
},
"input_uri": {
"title": "Input Uri",
"type": "string"
},
"job_id": {
"title": "Job Id",
"type": "string"
},
"output_uri": {
"title": "Output Uri",
"type": "string"
},
"retryable": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": null,
"title": "Retryable"
},
"stage": {
"anyOf": [
{
"enum": [
"download",
"transcribe",
"upload",
"thermal_shutdown"
],
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Stage"
},
"started_at": {
"format": "date-time",
"title": "Started At",
"type": "string"
},
"status": {
"enum": [
"completed",
"failed"
],
"title": "Status",
"type": "string"
}
},
"required": [
"job_id",
"input_uri",
"output_uri",
"status",
"started_at"
],
"title": "JobSummaryEntry",
"type": "object"
}
},
"description": "One summary JSON per accepted batch.\n\nWritten to the caller-supplied ``summary_uri`` after every job in the\nbatch has reached a terminal state. The canonical surface for the\norchestrator to discover batch outcomes \u2014 successful job transcripts are\nalready on the analysis pipeline's wake signal by the time this is\nwritten.",
"properties": {
"batch_id": {
"title": "Batch Id",
"type": "string"
},
"completed_at": {
"format": "date-time",
"title": "Completed At",
"type": "string"
},
"jobs": {
"items": {
"$ref": "#/$defs/JobSummaryEntry"
},
"title": "Jobs",
"type": "array"
},
"schema_version": {
"default": "1.0.0",
"description": "Semver of the summary schema.",
"title": "Schema Version",
"type": "string"
},
"submitted_at": {
"format": "date-time",
"title": "Submitted At",
"type": "string"
},
"totals": {
"$ref": "#/$defs/BatchTotals"
}
},
"required": [
"batch_id",
"submitted_at",
"completed_at",
"jobs",
"totals"
],
"title": "BatchSummary",
"type": "object"
}
Loading