# Architecture Speech-Text Data Aligners is a library-first forced-alignment framework. The core contract accepts WAV audio plus a known, authoritative transcript and returns backend-neutral timed words. The CLI is only a composition and presentation layer. The mandatory design rules are defined in the [modular architecture contract](MODULAR_ARCHITECTURE_CONTRACT.md) and the [aligner engineering contract](ALIGNER_ENGINEERING_CONTRACT.md). ## Layers and Dependency Direction ```text CLI --------------------> Application --------------------> Core | ^ +----------> Data -------------+ +----------> Benchmarking -----+ +----------> Runtime ----------+ CLI -- lazy composition --> Concrete Backends | | +------------> Core +------------> Runtime ``` In compact form: ```text CLI -> Application -> Core -> Data -> Benchmarking -> Runtime Concrete Backends -> Core / Runtime ``` The enforced consequences are: - Core does not import application, data, benchmarking, CLI, or concrete backends. - Data and benchmarking do not depend on concrete backends. - Application services receive an `AlignmentBackend` protocol instance; they do not branch on NeMo, MFA, or WhisperX names. - Concrete backend packages do not import one another. - The registry stores lazy dotted factories so unavailable optional runtimes do not break backend-neutral imports or sibling backends. - The CLI delegates annotation and benchmarking to reusable Python services. ## Current Package Tree ```text src/speech_text_data_aligners/ |-- __init__.py public backend-neutral facade |-- application/ | |-- annotate.py annotation orchestration and publication policy | `-- benchmark.py identical-request benchmark orchestration |-- backends/ | |-- registry.py immutable lazy backend composition | |-- nemo/ | | |-- backend.py neutral adapter | | |-- config.py typed configuration | | |-- manifest.py reference JSONL and output-manifest parsing | | |-- runner.py isolated NFA execution | | `-- ctm.py word CTM parsing and mapping | |-- mfa/ | | |-- backend.py neutral adapter | | |-- config.py typed configuration | | |-- corpus.py temporary WAV/LAB corpus | | |-- runner.py isolated MFA execution | | `-- textgrid.py word-tier parsing and mapping | `-- whisperx/ | |-- backend.py neutral adapter | |-- config.py typed configuration | |-- segments.py full-WAV authoritative segments | |-- provider.py isolated-worker transport | |-- worker.py lazy heavyweight native runtime | `-- parser.py native word-dictionary parsing and mapping |-- benchmarking/ | |-- metrics.py sparse-gold and pairwise metrics | `-- reports.py JSON/CSV/Markdown report rendering |-- cli/ | |-- main.py command dispatch | |-- annotate.py annotation argument adapter | `-- benchmark.py benchmark argument adapter |-- core/ | |-- models.py immutable neutral values and provenance | |-- protocols.py injected backend contracts | |-- errors.py project exception taxonomy | |-- normalization.py lexical plans and monotonic reconciliation | |-- validation.py result and publication-path invariants | `-- extraction.py six first/last output fields |-- data/ | |-- audio.py WAV resolution and lightweight probing | `-- metadata.py preserving, atomic CSV I/O `-- runtime/ |-- process.py shell-free injected subprocess boundary |-- artifacts.py temporary and retained artifact lifecycle `-- receipts.py hashes and run provenance ``` Package-marker `__init__.py` files not shown above are deliberately empty. The root `__init__.py` is the tested public facade. ## Backend Isolation and Native Containment ```text PARENT PROCESS Python caller or CLI | v backend-neutral application API | v AlignmentBackend protocol | v concrete adapter (NeMo | MFA | WhisperX) | | injected process/provider boundary v +------------------------------------------------------+ | ISOLATED NATIVE RUNTIME | | NeMo NFA process | MFA process | WhisperX worker | | Heavy optional dependencies and model lifecycle | +------------------------------------------------------+ | | native files / native dictionaries v adapter-local builder, parser, and reconciliation | | only neutral records cross this point v AlignmentResult | AlignmentFailure | diagnostics | provenance ``` NeMo manifests, output manifests, and CTM rows remain inside `backends.nemo`. MFA corpus labels and TextGrid objects remain inside `backends.mfa`. WhisperX segment payloads and native result dictionaries remain inside `backends.whisperx`. NeMo CTM, MFA TextGrid, and WhisperX native dictionaries never escape their adapters; callers receive only backend-neutral models. The parent process does not import heavyweight NeMo, MFA, WhisperX, Torch, or Torchaudio packages. NeMo and MFA run through the shared shell-free process boundary. WhisperX runs in a dedicated worker that imports its heavy stack only after invocation. ## Transcript-to-Result Data Flow ```text authoritative transcript | v backend-specific reference representation | v native timed words | v shared monotonic reconciliation | v shared validation | v AlignmentResult ``` The authoritative `en_transcript` remains unchanged throughout. A backend may normalize or expand text only through a reversible plan that retains ownership of original lexical words. Shared reconciliation requires complete monotonic coverage, and shared validation rejects non-finite, negative, reversed, overlapping, incomplete, or out-of-audio timestamps. It never clamps, interpolates, or invents a timestamp. ## Reuse and Composition The root facade exposes reusable annotation and benchmark services. Applications may inject any object satisfying `AlignmentBackend`, including a lightweight test or custom backend. The default registry is a convenience for the CLI, not a dependency of the application layer. Benchmarking consumes the same neutral results as annotation. Native parsing, transcript mapping, CSV I/O, metric calculation, report rendering, and process execution each have one owning layer, so adding another adapter does not require changes to established backend-neutral behavior. Architecture is enforced by deterministic AST tests and Import Linter contracts. The accepted audit and complete dependency evidence are recorded in the [Stage 5 final acceptance report](STAGE_5_FINAL_ACCEPTANCE_REPORT.md).