208 lines
12 KiB
Markdown
208 lines
12 KiB
Markdown
# 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:
|
|
|
|
- [CLI reference](../cli.md)
|
|
- [Configuration](../config.md)
|
|
- [Operations](../operations.md)
|
|
- [Troubleshooting](../troubleshooting.md)
|
|
- [Integration docs](../integrations/subprocess.md)
|
|
- [Internal docs](../internal/overview.md)
|
|
|
|
## 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](../config.md), [CLI reference](../cli.md), [Operations](../operations.md), and integration docs under [`docs/integrations/`](../integrations/subprocess.md) 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](./documentation.md). 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.
|