Files
ansible-workspace-dnd/docs/roadmap/features/0002-audita-source-installation-and-configuration.md

250 lines
12 KiB
Markdown

# Feature 0002: Audita Source Installation and Configuration
Status: done
## Summary
Provide a small, independently usable `rakestraw.audita` role that installs
Audita from a pinned Git tag, builds its executable on the managed host, and
offers an ergonomic field-specific interface for its versioned YAML
configuration. Unspecified optional fields are omitted so Audita retains
ownership of its application defaults.
## Problem or Opportunity
The completed source-installation flow is concise and correct, but the initial
configuration interface exposes only one `audita_config` mapping. That requires
every caller to know and reproduce Audita's native nested schema, and it does
not provide the ordinary role ergonomics expected for inventory variables.
The role should expose documented variables for individual settings and render
only values expressly selected by the caller. This permits straightforward
`host_vars`, `group_vars`, play variables, and suite-role overrides while
allowing upstream default changes to take effect automatically when a setting
is not managed by Ansible.
## Scope
- Retain the completed Ubuntu 26.04 `amd64` and `arm64` source installation.
- Retain default tag `v0.9.1`, Go Snap channel `1.26/stable`, source path
`/usr/local/src/audita`, and binary path `/usr/local/bin/audita`.
- Retain rebuild triggers of changed Git checkout or absent binary.
- Replace the complete `audita_config` mapping with typed, field-specific
configuration variables.
- Always render the required configuration schema version, defaulting to `1`.
- Define every optional configuration variable as `null` by default and omit
its YAML field when it remains null.
- Render nested YAML sections only when at least one setting in that section is
non-null.
- Manage `/usr/local/etc/audita/config.yml` from a Jinja template as
`root:root` mode `0644`.
- Keep defaults, argument specifications, template, README, metadata,
dependency declaration, and focused tests consistent with this contract.
## Non-goals
- Copying Audita's built-in values into role defaults or the default rendered
file.
- D&D-specific model selection, concurrency, thresholds, transcript context,
or other suite policy.
- A parallel mapping-based configuration escape hatch or merge/precedence
rules between two configuration interfaces.
- API keys or other secret values. Variables may select environment-variable
names, but the role does not manage their values.
- Creation of the `narratio` account or management of runtime, campaign,
glossary, transcript, diagnostics, or secret-delivery infrastructure.
- Services, scheduling, removal behavior, pipeline composition, prebuilt
artifacts, or cross-compilation.
- Production execution of Audita for build or configuration validation.
- Fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, compiler inspection, or out-of-band drift detection.
## Target End State
With no configuration overrides, the role writes the minimal valid document:
```yaml
version: 1
```
When a caller sets an optional role variable, the corresponding native Audita
field appears in the correct YAML section. Fields whose variables remain null
are absent, including their parent sections when no child is selected. Empty
lists, empty strings, zero, and other expressly supplied non-null values are
rendered rather than mistaken for omission and are left for Audita to validate.
Installation and configuration converge independently. A configuration-only
change does not rebuild the binary, and an immediate repeat reports no changes.
Repository-local tests execute Audita to verify the installed version and
validate both minimal and representative managed configurations.
## Repository Ownership
- `ansible-role-audita` owns installation, the public configuration interface,
template, metadata, README, and repository-local tests.
- `../audita` is the read-only authority for build, CLI, configuration schema,
and application-default contracts.
- `rakestraw-ansible` is a read-only style reference for field-specific role
variables and conditional templates; its historical values are not
authoritative defaults.
- `ansible-role-dnd-pipeline` will later own D&D-specific overrides supplied
through the standalone role variables.
- `ansible-workspace-dnd` owns this roadmap, the staged plan, and aggregate
status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- Tag `v0.9.1` resolves to
`a84941d68168a1ed9ea7423b6477ae8218be73f9` and retains the build contract
already implemented and validated through role commit `3a8c21f`.
- Audita's strict schema version is `1`; all other top-level fields are
optional and overlay application defaults.
- `audita_config_version` names the schema version so `audita_version` remains
unambiguously the selected application release.
- Optional variables are present in role defaults with YAML null values. This
documents the interface and enables argument validation without emitting
upstream defaults.
- Template conditions use `is not none`, not truthiness, so expressly supplied
falsey values are rendered.
- String and list values must be safely encoded as YAML values rather than
interpolated with hand-written quoting.
- A parent mapping is emitted only when at least one corresponding child value
is non-null.
- The role does not validate Audita's semantic constraints during production
convergence. Native validation remains integration-test behavior.
- Task-level `become: true`, `community.general` 13.3.0, and all existing
installation decisions remain unchanged.
## Fixed Public Interface
Retain these installation variables:
| Variable | Default |
| --- | --- |
| `audita_version` | `v0.9.1` |
| `audita_repository_url` | `https://gitea.maximumdirect.net/eric/audita.git` |
| `audita_source_dir` | `/usr/local/src/audita` |
| `audita_binary_path` | `/usr/local/bin/audita` |
| `audita_manage_build_dependencies` | `true` |
| `audita_go_snap_channel` | `1.26/stable` |
| `audita_go_binary` | `/snap/bin/go` |
| `audita_config_path` | `/usr/local/etc/audita/config.yml` |
Provide these configuration variables:
| Variable | Default | Native field |
| --- | --- | --- |
| `audita_config_version` | `1` | `version` |
| `audita_pipeline_modules` | `null` | `pipeline.modules` |
| `audita_output_schema` | `null` | `output.schema` |
| `audita_llm_proposal_base_url` | `null` | `llm.proposal.base_url` |
| `audita_llm_proposal_model` | `null` | `llm.proposal.model` |
| `audita_llm_proposal_api_key_env` | `null` | `llm.proposal.api_key_env` |
| `audita_llm_proposal_timeout` | `null` | `llm.proposal.timeout` |
| `audita_llm_proposal_max_retries` | `null` | `llm.proposal.max_retries` |
| `audita_llm_validation_base_url` | `null` | `llm.validation.base_url` |
| `audita_llm_validation_model` | `null` | `llm.validation.model` |
| `audita_llm_validation_api_key_env` | `null` | `llm.validation.api_key_env` |
| `audita_llm_validation_timeout` | `null` | `llm.validation.timeout` |
| `audita_llm_validation_max_retries` | `null` | `llm.validation.max_retries` |
| `audita_concurrency_total_llm` | `null` | `concurrency.total_llm` |
| `audita_concurrency_proposal_llm` | `null` | `concurrency.proposal_llm` |
| `audita_concurrency_validation_llm` | `null` | `concurrency.validation_llm` |
| `audita_chunking_target_sections` | `null` | `chunking.target_sections` |
| `audita_chunking_max_section_tokens` | `null` | `chunking.max_section_tokens` |
| `audita_chunking_min_section_tokens` | `null` | `chunking.min_section_tokens` |
| `audita_normalization_max_segment_gap` | `null` | `normalization.max_segment_gap` |
| `audita_normalization_ellipsis_gap` | `null` | `normalization.ellipsis_gap` |
| `audita_normalization_max_segment_duration` | `null` | `normalization.max_segment_duration` |
| `audita_normalization_max_segment_tokens` | `null` | `normalization.max_segment_tokens` |
| `audita_thresholds_glossary` | `null` | `thresholds.glossary` |
| `audita_thresholds_homophones` | `null` | `thresholds.homophones` |
| `audita_thresholds_spoken_word` | `null` | `thresholds.spoken_word` |
| `audita_thresholds_grammar` | `null` | `thresholds.grammar` |
| `audita_context_description` | `null` | `context.description` |
| `audita_diagnostics_work_dir` | `null` | `diagnostics.work_dir` |
| `audita_diagnostics_retention` | `null` | `diagnostics.retention` |
The argument specification types values according to the native field shape.
Duration-like fields accept strings or numeric seconds as supported by Audita;
do not narrow the application contract unnecessarily.
## Simplest Viable Implementation
Retain the existing nine-task installation flow. Make only these production
changes:
1. Replace `audita_config` in defaults and argument specifications with the
field-specific variables above.
2. Add `templates/config.yml.j2`, always rendering `version` and conditionally
rendering every optional field and necessary parent mapping.
3. Replace the final `ansible.builtin.copy` task with one
`ansible.builtin.template` task using the existing destination, ownership,
and mode.
Do not add configuration assembly facts, nested merge filters, validation
commands, preliminary file probes, or multiple configuration tasks. The
template is the direct expression of the selected configuration state.
## Rationale and Alternatives
Field-specific variables are the ordinary ergonomic interface for inventory
and composing roles. Nullable defaults make that interface discoverable and
typed without freezing a duplicate copy of Audita's application defaults into
Ansible. Conditional rendering also preserves the distinction between an
unset field and a caller intentionally supplying a falsey value.
Leaving variables entirely undefined would produce the same file but weaken
interface documentation and argument validation. Section-level dictionaries
would shorten the template but require callers to understand more of the
native nested schema. Retaining `audita_config` beside field variables would
require unneeded merge and precedence semantics. None is preferable to the
single field-specific interface.
## Acceptance Criteria
- All existing source-installation and platform acceptance criteria continue
to pass without production task-flow expansion.
- Defaults and argument specifications contain exactly the eight installation
variables and thirty configuration variables in the Fixed Public Interface.
- No `audita_config` compatibility variable remains.
- Default convergence writes a YAML mapping containing exactly `version: 1`.
- Every optional field is absent when its variable is null.
- Setting a representative value in every configuration section renders the
correct nested native fields and passes `audita config validate`.
- Explicit falsey non-null values are rendered rather than omitted; semantic
validity remains Audita's responsibility.
- Configuration changes run the template task but not the build task and
reach an unchanged immediate repeat.
- The installed configuration remains a regular file owned by `root:root`
with mode `0644`.
- Production tasks do not invoke Audita, inspect the existing configuration,
or construct intermediate configuration state.
- The README documents each variable, null-as-unmanaged behavior, safe secret
environment-variable naming, and the distinction between application and
suite defaults.
- Syntax checking, production-profile ansible-lint, complete integration
testing, native minimal and representative configuration validation, and
clean repeated runs pass.
- Only `ansible-role-audita` and the workspace control repository change.
## Dependencies and Follow-up Work
The existing Audita role through commit `3a8c21f` is the implementation
baseline. The managed host and test prerequisites are unchanged.
The configuration amendment was completed in `ansible-role-audita` commits
`e61f02f` and `847c4c3` and validated by its complete integration suite. The
proposed Notarius roadmap should use the same nullable field-specific approach
where appropriate.
## Potential Future Hardening
- Validate configuration during production convergence if later operating
requirements explicitly select that behavior.
- Manage secret environment delivery, diagnostics paths, runtime accounts, or
services as separate suite-level or application-level features.
- Detect source signatures, compiler drift, or out-of-band binary changes if
the threat model changes.