Files
audita/docs/policy/architecture.md

12 KiB

Architecture Policy

Purpose

This document defines Audita's development architecture and invariants for maintainers and LLM coding agents. It describes how the project is intended to be changed safely, based on behavior implemented in this repository today.

User-facing behavior belongs in the README and focused runtime docs. Future or proposed work belongs only under docs/roadmap/.

Project Shape

Audita is a single-process Go CLI for transcript polishing. The executable entrypoint is cmd/audita; command handling lives in internal/cli.

The implemented audita process flow is:

  1. load effective config;
  2. read and validate transcript JSON and glossary YAML;
  3. normalize transcript segments;
  4. chunk the working transcript into sections;
  5. resolve configured module instances;
  6. run correction modules and validator chains;
  7. apply approved proposals deterministically;
  8. write transcript output, reports, and diagnostics artifacts.

The current built-in modules are glossary, homophones, spoken_word, and grammar. The default configured module sequence repeats glossary.

For external behavior and compatibility details, prefer links to existing behavior docs:

Core Design Principles

  • Hexagonal architecture: keep domain behavior behind narrow internal contracts. CLI, filesystem, config loading, diagnostics writing, and LLM transport are adapters around the core processing flow.
  • Composable modules and validators: correction stages and validators should remain small, explicit, and independently testable.
  • Deterministic orchestration around LLM calls: LLM responses are nondeterministic inputs. Proposal indexing, validator ordering, proposal application, reports, and output serialization must remain deterministic.
  • Bounded and observable concurrency: use the implemented schedulers and configured concurrency limits for LLM call sites. Preserve utilization diagnostics when changing scheduling or orchestration.
  • Conservative correction behavior: validate proposed corrections before application; apply accepted proposals through deterministic apply-time safety checks.
  • Standard-library-first: prefer the Go standard library. Narrow third-party dependencies are acceptable when they materially improve maintainability, such as gopkg.in/yaml.v3 for YAML parsing.
  • Current-behavior documentation: non-roadmap docs must describe implemented behavior only.

Architectural Boundaries

internal/core owns domain data handling and stable runtime contracts that do not require CLI or provider transport knowledge:

  • config defaults, loading, validation, redaction, and catalogs;
  • transcript and glossary schemas;
  • normalization and chunking;
  • output-schema encoding;
  • diagnostics artifact naming and run-directory helpers;
  • public process report shapes.

internal/framework owns orchestration contracts and reusable runtime mechanics:

  • module and validator interfaces;
  • proposal generation, proposal application, and prompt context;
  • runner orchestration;
  • LLM scheduler, OpenAI-compatible adapter, redaction helpers, and diagnostics writers;
  • structured response schema registry;
  • process report and correction-ledger assembly.

internal/modules/* owns module-specific correction stages. internal/validators/* owns built-in validator implementations, registry, chains, and execution-class metadata. internal/prompts owns embedded prompt assets and prompt metadata.

internal/cli owns command parsing, exit codes, stdout/stderr behavior, config command behavior, filesystem input/output wiring, and top-level process orchestration. CLI concerns should not move into modules, validators, or schema logic.

Tests should stay close to the behavior they protect. Shared test helpers are acceptable when they remove clear duplication without hiding module-specific behavior.

Modules and Validators

Modules implement contracts.TranscriptModule. A module must provide:

  • a stable key;
  • a replacement policy;
  • a validator chain;
  • proposal generation from explicit request inputs.

Module packages should stay separate. Do not collapse module-specific prompts, scope, or validation choices into a broad generic stage abstraction.

Validators implement the shared validator contract and return one decision per candidate proposal. Deterministic validators and LLM-backed validators are both composable chain elements. Validator identity and execution class metadata are stable enough to affect ordering, diagnostics, reports, and correction-ledger classification.

Future module or validator changes should preserve:

  • explicit inputs and outputs;
  • no hidden global state;
  • explicit config dependencies;
  • deterministic proposal index handling;
  • validation before final mutation;
  • stable reason codes and validator keys where already exposed.

LLM Integration and Concurrency

LLM calls are external effects behind narrow contracts. Production structured completions use contracts.StructuredLLMClient; the implemented provider adapter is OpenAI-compatible HTTP code in internal/framework/llm.

Structured response schemas are registered in internal/framework/responseschema. Provider-side schema enforcement is not a substitute for local validation: Audita still validates proposal structure, validator decision cardinality, and apply-time safety.

Concurrency is bounded by configured scheduler limits:

  • total LLM concurrency;
  • proposal LLM concurrency;
  • validation LLM concurrency.

The scheduler is context-aware and releases permits on success, failure, and cancellation. Runner code may collect section-level work concurrently, but transcript mutation is applied later in deterministic proposal-index order.

Diagnostics for LLM interactions should be useful for debugging without leaking configured secrets. Use the existing redaction helpers and llm.ConfiguredSecrets.

State, Inputs, and Outputs

Audita does not implement resume, checkpoint, manifest, or remote storage behavior. Runtime state is in memory plus per-run diagnostics artifacts written under the configured work directory.

Transcript input accepts the implemented JSON forms documented in the public contract. Parsed source transcripts are normalized into Audita's internal transcript shape before chunking and module execution.

Proposals and validator decisions are intermediate runtime data. Approved proposals are applied through internal/framework/proposals, which clones transcript state, orders by proposal index, and records applied or skipped changes.

Transcript output is encoded through internal/core/outputschema. Reports and correction ledgers are machine-readable artifacts derived from runner outputs; their public shape should not be changed casually.

Configuration and CLI Boundaries

Config behavior is owned by internal/core/config; command usage and process wiring are owned by internal/cli.

audita process uses implemented precedence: defaults, config file, environment, then CLI flags. config validate validates defaults plus a file config and intentionally does not apply environment overrides. config print-effective applies defaults, file config, and environment overrides, then prints redacted JSON.

Do not duplicate full CLI or config reference material here. Use Configuration, CLI reference, Operations, and integration docs under docs/integrations/ for current external behavior.

When adding config fields or CLI flags, update:

  • config defaults, file/env/CLI application, and validation;
  • CLI flag extraction if applicable;
  • redaction when secrets are involved;
  • tests for precedence and source-specific behavior;
  • user-facing docs if external behavior changes.

Errors, Logging, and Diagnostics

Errors should be phase-specific enough for CLI users and subprocess callers. The CLI writes human-readable errors to stderr and preserves transcript JSON-only stdout behavior on successful stdout output.

Run diagnostics are best-effort after run-directory creation. Failed runs are retained. Successful run retention follows the implemented work-dir retention policy.

Diagnostics and reports must not leak configured LLM secrets. Config redaction and LLM payload/error redaction are separate responsibilities and should remain separate.

Process reports, diagnostics metadata, utilization diagnostics, and correction ledgers are part of the public contract. Prefer additive, compatible changes.

Testing Expectations

Use targeted package tests for touched behavior and go test ./... for substantial changes.

When changing modules, inspect or add:

  • package-local module tests under internal/modules/*;
  • prompt rendering or proposal-generation tests when prompt inputs change;
  • parity or release fixtures when public output behavior changes.

When changing validators, inspect or add:

  • validator package tests;
  • registry and chain tests under internal/validators;
  • framework validator tests for batching, malformed output, diagnostics, and cardinality.

When changing LLM integration or concurrency, inspect or add:

  • internal/framework/llm scheduler/client/redaction tests;
  • internal/framework/runner orchestration and utilization tests;
  • structured-output malformed classification tests.

When changing config, CLI, schema, output, reports, or diagnostics, inspect or add:

  • internal/core/config tests;
  • CLI tests under internal/cli;
  • schema and output-schema tests under internal/core;
  • report, diagnostics, parity, and release-fixture tests.

Dependency Policy

Audita should remain dependency-light. Prefer standard-library solutions for CLI parsing, HTTP, JSON, filesystem, synchronization, and tests.

Third-party dependencies should be narrow, justified, and preferably de facto standard for their purpose. YAML parsing is the current direct dependency exception.

Do not add broad frameworks for CLI, dependency injection, workflow orchestration, logging, or plugin systems without a concrete implemented need and focused tests.

Documentation Expectations

Follow Documentation Policy. Architecture policy must stay concise and aligned with implemented behavior.

Do not use architecture docs as changelogs. Do not describe planned modules, adapters, modes, persistence, or configuration unless they are implemented. Put future work under docs/roadmap/.

Architectural Invariants

  • Keep LLM transport behind StructuredLLMClient and framework adapter boundaries.
  • Keep correction modules narrowly scoped and package-separated.
  • Keep validators modular, composable, and identified by stable keys.
  • Keep CLI/config/filesystem concerns out of module and validator domain logic.
  • Preserve deterministic transcript mutation and output handling around nondeterministic LLM calls.
  • Keep LLM concurrency bounded, configurable, and observable where implemented.
  • Keep run diagnostics and reports redacted and machine-readable.
  • Keep public CLI, config, output-schema, diagnostics, report, prompt, module, and validator contracts stable unless a change is explicit and tested.
  • Prefer small shared helpers over broad rewrites.
  • Avoid new dependencies unless they are narrow and clearly justified.

Non-Goals

  • No plugin framework is implemented.
  • No generic workflow engine is implemented.
  • No resume, checkpoint, manifest, or remote storage system is implemented.
  • No multi-process service mode is implemented.
  • No provider SDK abstraction beyond the current structured LLM client contract and OpenAI-compatible HTTP adapter is implemented.