Complete the Audita amendment and resume Notarius planning

This commit is contained in:
2026-09-08 14:03:14 +00:00
parent 5713ce582e
commit a3af153895
6 changed files with 528 additions and 326 deletions

View File

@@ -6,243 +6,244 @@ Status: done
Provide a small, independently usable `rakestraw.audita` role that installs
Audita from a pinned Git tag, builds its executable on the managed host, and
manages its versioned YAML configuration. Follow the module-driven Seriatim
pattern while adding only the configuration behavior that distinguishes
Audita.
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 `ansible-role-audita` repository currently contains only its initial
placeholder files. Audita needs a standalone installer before the suite role
can compose the transcript-processing pipeline and supply D&D-specific runtime
policy.
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.
An earlier implementation direction depended on the superseded Seriatim
fingerprint, sidecar-state, staged-build, and corruption-recovery architecture.
This roadmap replaces that direction with a concise implementation that trusts
Ansible modules, rebuilds only for required conditions, and keeps production
role tasks separate from integration verification.
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
- Implement `ansible-role-audita` as a conventional standalone role.
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
- Install Git and the official Go Snap with classic confinement when build
dependency management is enabled.
- Default the Go Snap channel to `1.26/stable`.
- Check out immutable Audita tag `v0.9.1` by default under the root-owned path
`/usr/local/src/audita`.
- Build Audita with its upstream release build contract and install the native
executable at `/usr/local/bin/audita`.
- Rebuild when the Git checkout changes or the binary is absent.
- Converge the installed binary to `root:root` ownership and mode `0755`.
- Manage a versioned Audita YAML configuration at
`/usr/local/etc/audita/config.yml`, owned by `root:root` with mode `0644`.
- Default the managed configuration to the minimal valid mapping
`{"version": 1}`, allowing Audita's own defaults to govern application
behavior.
- Keep role defaults, argument specifications, README, metadata, dependency
declaration, and focused local tests consistent with this contract.
- 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. The suite-level role will provide those overrides.
- A separate Ansible variable for every field in Audita's configuration
schema.
- API keys, secret values, environment files, or another secret-delivery
mechanism. Configuration may name environment variables but must not contain
their secret values.
- Creation or management of the `narratio` account, operator groups, campaign
data, glossaries, transcript data, or diagnostics directories.
- Installation or configuration of another pipeline application.
- Services, scheduling, removal behavior, or pipeline composition.
- Prebuilt release artifacts or cross-compilation.
- Production execution of Audita to validate the build or configuration.
- Detection of out-of-band binary modification, compiler changes, or fixed
build-command changes.
- Build fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, or special recovery for malformed or adversarial host state.
- A shared build helper role or dedicated platform-matrix infrastructure.
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
On an Ubuntu 26.04 `amd64` or `arm64` host, applying the role with defaults
installs or confirms Git and Go, checks out Audita `v0.9.1` at
`/usr/local/src/audita`, builds `/usr/local/bin/audita`, and writes
`/usr/local/etc/audita/config.yml`. Source and installed files have the stated
root ownership and permissions, and the configuration contains `version: 1`.
With no configuration overrides, the role writes the minimal valid document:
An immediate second application reports no changes. A changed Git checkout or
missing binary causes one build; configuration changes converge through the
ordinary file-management module without rebuilding Audita. Repository-local
tests execute the installed CLI to verify the build and validate the managed
configuration.
```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 the role implementation, public interface,
configuration rendering, metadata, dependency declaration, README, and
repository-local validation.
- `../audita` is the read-only authority for the build, CLI, and configuration
contracts.
- `rakestraw-ansible` is a read-only style and configuration-policy reference.
- `ansible-role-dnd-pipeline` will later own the D&D-specific values supplied
through the standalone role's configuration interface.
- `ansible-workspace-dnd` owns this roadmap, the eventual staged implementation
plan, and aggregate status.
- `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
- The selected release is tag `v0.9.1`, which resolves to commit
`a84941d68168a1ed9ea7423b6477ae8218be73f9`.
- Tags `v0.9.0` and `v0.9.1` resolve to the same commit, so `v0.9.0` cannot
exercise checkout-change rebuilding. Focused integration may temporarily
select buildable commit `46b7356a3b54a2771ce9a617e4fa3e8d13728cac`
before restoring the default tag.
- The tag declares Go 1.24.0. The suite-standard Go Snap channel remains
`1.26/stable`.
- The upstream release build uses package
`gitea.maximumdirect.net/eric/audita/cmd/audita`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags `-s -w -X
gitea.maximumdirect.net/eric/audita/internal/buildinfo.Version=<version>`.
- Audita exposes no release-version command needed by production convergence.
The role uses only checkout change and binary absence as build triggers.
- Audita configuration schema version `1` is strict. The native command
`audita config validate --config <path>` reports `config is valid` for a
valid file and is used only by tests.
- Audita's default configuration search order prefers
`/usr/local/etc/audita/config.yml` over `/etc/audita/config.yml`; the role
manages the preferred path.
- Configuration is exposed as one mapping rather than many field-specific
variables. This preserves Audita's schema and gives the suite role one clear
override boundary.
- Configuration contains no secrets by default. Consumers use Audita's
`api_key_env` fields and arrange secret environment variables outside this
feature.
- Tasks that install dependencies or manage root-owned application state use
task-level `become: true`.
- `community.general` is an approved dependency and supplies Snap management;
pin version `13.3.0` in the role's collection requirements.
- 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
| Variable | Default | Purpose |
| --- | --- | --- |
| `audita_version` | `v0.9.1` | Git revision and release value supplied to the build |
| `audita_repository_url` | `https://gitea.maximumdirect.net/eric/audita.git` | Source repository |
| `audita_source_dir` | `/usr/local/src/audita` | Managed source checkout |
| `audita_binary_path` | `/usr/local/bin/audita` | Installed executable |
| `audita_manage_build_dependencies` | `true` | Whether to install Git and Go |
| `audita_go_snap_channel` | `1.26/stable` | Go Snap channel |
| `audita_go_binary` | `/snap/bin/go` | Go executable used for the build |
| `audita_config_path` | `/usr/local/etc/audita/config.yml` | Managed configuration file |
| `audita_config` | `{"version": 1}` | Complete versioned configuration mapping |
Retain these installation variables:
The package, build flags, linker symbol, environment values, file ownership,
and file modes are fixed implementation details. The selected version is both
the Git revision and the value supplied to the upstream linker flag.
| 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
The expected implementation is approximately nine ordinary tasks in one
readable task file:
Retain the existing nine-task installation flow. Make only these production
changes:
1. Assert Ubuntu 26.04 and architecture `x86_64` or `aarch64`.
2. Install Git with `ansible.builtin.apt`, including
`cache_valid_time: 3600`, when dependency management is enabled.
3. Install the classic Go Snap from `audita_go_snap_channel` with
`community.general.snap` when dependency management is enabled.
4. Create the source, binary, and configuration parent directories with one
`ansible.builtin.file` loop.
5. Check out `audita_version` with `ansible.builtin.git`, `force: true`, and
register the module result.
6. Inspect whether `audita_binary_path` exists with `ansible.builtin.stat`.
7. Run the upstream Go build through `audita_go_binary` when the checkout
changed or the binary is absent.
8. Converge recursive source ownership and binary ownership and mode with one
item-driven `ansible.builtin.file` loop.
9. Serialize `audita_config` as YAML and manage `audita_config_path` with
`ansible.builtin.copy`.
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.
Apply task-level privilege escalation only to tasks that require it. Use
`argv` for the build command, and put its two conditions directly on the build
task. Do not add a rebuild fact, handler, handler flush, executable discovery,
compiler interrogation, configuration preflight, or post-operation validation
to production tasks.
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
Audita's installation mechanics are intentionally the same as Seriatim's:
declarative dependency and checkout management surrounding one imperative
build command. The binary existence probe is justified because Ansible cannot
infer whether that command's output exists; no other build-state model is
needed.
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.
A single configuration mapping is smaller and more durable than duplicating
Audita's evolving schema as dozens of role variables. A minimal default mapping
produces a valid configuration while preserving upstream defaults. The future
suite role can supply its complete D&D-specific mapping without coupling the
standalone role to one deployment.
Managing the preferred `/usr/local/etc` path follows the application's own
discovery order and keeps locally installed software and its configuration
together. `/etc/audita/config.yml` remains an unmanaged application fallback.
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
- Unsupported distributions, Ubuntu releases, and architectures fail before
application state is modified.
- Default execution on the local Ubuntu 26.04 host installs or confirms Git
and Go and checks out Audita tag `v0.9.1` at commit
`a84941d68168a1ed9ea7423b6477ae8218be73f9`.
- The role builds with the fixed upstream contract and installs
`/usr/local/bin/audita` as `root:root` mode `0755`.
- The managed source checkout is recursively owned by `root:root`.
- The default configuration is a valid schema-version `1` document at
`/usr/local/etc/audita/config.yml`, owned by `root:root` with mode `0644`.
- Repository-local tests successfully execute the installed CLI and receive
`config is valid` when validating the managed configuration.
- An immediate second role run reports no changes.
- A missing binary causes one rebuild followed by an unchanged run.
- A changed checkout causes one rebuild followed by an unchanged run.
- A configuration change updates only configuration state and does not rebuild
the binary.
- Dependency opt-out accepts a caller-supplied `audita_go_binary`.
- A play connecting as an ordinary sudo-capable user can apply the role without
play-level privilege escalation.
- Defaults and argument specifications contain exactly the nine variables in
the Fixed Public Interface.
- The implementation contains no production CLI validation, fingerprints,
checksums, sidecar build state, manual Git reset or clean commands, or probes
before state already managed by APT, Snap, `file`, `git`, or `copy`.
- Syntax checking, production-profile ansible-lint, focused local convergence,
configuration validation, and clean repeated runs pass.
- Role documentation describes the actual behavior, dependency opt-out,
complete configuration mapping, privilege use, and local test effects.
- No repository other than `ansible-role-audita` and the workspace control
repository is modified.
- 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 managed host requires access to the Audita Git repository, Ubuntu Snap
infrastructure, and Go module sources. Runtime processing also requires a
glossary, transcript inputs, LLM endpoints, and secret environment variables;
those are consumers' or later suite-level features, not installation
dependencies.
The existing Audita role through commit `3a8c21f` is the implementation
baseline. The managed host and test prerequisites are unchanged.
Implementation and focused integration coverage were completed in
`ansible-role-audita` commits `47f1852`, `d37f590`, and `3a8c21f`. The D&D
pipeline role can now select concrete `audita_config` values through the
standalone role's complete-configuration interface.
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
- Build into a temporary path before replacing the installed executable.
- Verify source signatures or release checksums.
- Detect compiler, build-command, or out-of-band binary changes.
- Validate configuration during production convergence.
- Manage a dedicated runtime account, secret environment, diagnostics path,
service, or schedule if later operating requirements select them.
- Add dedicated Ubuntu release and architecture test matrices.
- 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.

View File

@@ -0,0 +1,253 @@
# Feature 0003: Notarius Source Installation and Configuration
Status: proposed
Planning note: the installation decisions are ready for review, but the
configuration interface was drafted before the nullable field-specific
convention was adopted. Revise that interface to follow
`docs/conventions.md` before approving this roadmap.
## Summary
Provide a small, independently usable `rakestraw.notarius` role that installs
Notarius from a pinned Git tag, builds its executable on the managed host, and
manages its versioned YAML configuration. Reuse the established module-driven
application-role pattern while leaving D&D pipeline policy to the suite-level
role.
## Problem or Opportunity
The `ansible-role-notarius` repository currently contains only its initial
placeholder files. Notarius is one of the five required pipeline applications
and needs an independently usable installation and native-configuration role
before the suite role can compose it with Seriatim, Audita, and the remaining
applications.
Seriatim and Audita have established the preferred source-build architecture.
Notarius can use the same concise task flow, with only its native configuration
and build contract differing.
## Scope
- Implement `ansible-role-notarius` as a conventional standalone role.
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
- Install Git and the official Go Snap with classic confinement when build
dependency management is enabled.
- Default the Go Snap channel to `1.26/stable`.
- Check out immutable Notarius tag `v0.6.0` by default under the root-owned
path `/usr/local/src/notarius`.
- Build Notarius with its upstream release build contract and install the
native executable at `/usr/local/bin/notarius`.
- Rebuild when the Git checkout changes or the binary is absent.
- Converge the installed binary to `root:root` ownership and mode `0755`.
- Manage a versioned Notarius YAML configuration at
`/usr/local/etc/notarius/config.yml`, owned by `root:root` with mode `0644`.
- Default the managed configuration to the minimal valid mapping
`{"version": 4}`, allowing Notarius's built-in defaults to govern behavior.
- Keep defaults, argument specifications, README, metadata, dependency
declaration, and focused local tests consistent with this contract.
## Non-goals
- A D&D pipeline definition, module selection, LLM profile, concurrency
policy, output paths, cache policy, or other suite-specific configuration.
- A separate Ansible variable for every Notarius configuration field.
- API keys, secret values, environment files, or another secret-delivery
mechanism.
- PromptKit profiles or other externally maintained prompt content.
- Creation or management of the `narratio` account, operator groups, campaign
data, runtime output, debug, cache, checkpoint, or transcript directories.
- Installation or configuration of another pipeline application.
- Services, scheduling, removal behavior, or pipeline composition.
- Prebuilt release artifacts or cross-compilation.
- Production execution of Notarius to validate the build or configuration.
- Detection of out-of-band binary modification, compiler changes, or fixed
build-command changes.
- Build fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, or special recovery for malformed or adversarial host state.
- A shared build helper role or dedicated platform-matrix infrastructure.
## Target End State
On an Ubuntu 26.04 `amd64` or `arm64` host, applying the role with defaults
installs or confirms Git and Go, checks out Notarius `v0.6.0` at
`/usr/local/src/notarius`, builds `/usr/local/bin/notarius`, and writes
`/usr/local/etc/notarius/config.yml`. Source and installed files have the
stated root ownership and permissions, and the configuration contains
`version: 4`.
An immediate second application reports no changes. A changed Git checkout or
missing binary causes one build; configuration changes converge independently
through the ordinary file-management module. Repository-local tests execute
the installed CLI to verify the selected build and validate the managed
configuration.
## Repository Ownership
- `ansible-role-notarius` owns the role implementation, public interface,
configuration serialization, metadata, dependency declaration, README, and
repository-local validation.
- `../notarius` is the read-only authority for build, CLI, and configuration
contracts.
- `rakestraw-ansible` is a read-only style and deployment-policy reference.
- `ansible-role-dnd-pipeline` will later own the D&D-specific configuration
supplied through the standalone role's mapping interface.
- `ansible-workspace-dnd` owns this roadmap, the eventual staged plan, and
aggregate status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- The selected release is tag `v0.6.0`, which resolves to commit
`77ae132e5609916da40dcd4fcc749c000a63cbac`.
- The release declares Go 1.25.5. The suite-standard Go Snap channel remains
`1.26/stable` and satisfies that requirement.
- The upstream release build uses package `./cmd/notarius`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flag
`-X gitea.maximumdirect.net/eric/notarius/internal/buildinfo.Override=<version>`.
- `notarius --version` prints `notarius <version>`. This is test evidence, not
an additional production rebuild trigger or post-build convergence task.
- Notarius configuration schema version 4 explicitly supports a document
containing only `version: 4`, with omitted values supplied by application
defaults.
- `notarius config validate --config <path>` validates a managed configuration
without requiring a pipeline selection. It is used only by tests.
- Configuration discovery uses an explicit CLI path, then `NOTARIUS_CONFIG`,
then `/usr/local/etc/notarius/config.yml`; the role manages the installed
default path.
- Configuration is exposed as one complete mapping. The suite role will later
supply the full D&D pipeline and operating policy through that boundary.
- Configuration contains no secrets by default. Consumers arrange any secret
environment variables outside this feature.
- Tasks that install dependencies or manage root-owned state use task-level
`become: true`.
- `community.general` supplies Snap management and is pinned to version
`13.3.0` in the role's collection requirements.
- Tag `v0.5.0`, commit
`61436d7c186af57b06004e090ceac898e83cdb71`, remains buildable with the same
Go requirement, package, linker symbol, and configuration schema and may be
used for focused checkout-change coverage before restoring `v0.6.0`.
## Fixed Public Interface
| Variable | Default | Purpose |
| --- | --- | --- |
| `notarius_version` | `v0.6.0` | Git revision and release value supplied to the build |
| `notarius_repository_url` | `https://gitea.maximumdirect.net/eric/notarius.git` | Source repository |
| `notarius_source_dir` | `/usr/local/src/notarius` | Managed source checkout |
| `notarius_binary_path` | `/usr/local/bin/notarius` | Installed executable |
| `notarius_manage_build_dependencies` | `true` | Whether to install Git and Go |
| `notarius_go_snap_channel` | `1.26/stable` | Go Snap channel |
| `notarius_go_binary` | `/snap/bin/go` | Go executable used for the build |
| `notarius_config_path` | `/usr/local/etc/notarius/config.yml` | Managed configuration file |
| `notarius_config` | `{"version": 4}` | Complete versioned configuration mapping |
The package, build flags, linker symbol, environment values, file ownership,
and modes are fixed implementation details. The selected version is both the
Git revision and the value supplied to the upstream linker flag.
## Simplest Viable Implementation
The expected implementation is approximately nine ordinary tasks in one
readable task file:
1. Assert Ubuntu 26.04 and architecture `x86_64` or `aarch64`.
2. Install Git with `ansible.builtin.apt`, including
`cache_valid_time: 3600`, when dependency management is enabled.
3. Install the classic Go Snap from `notarius_go_snap_channel` with
`community.general.snap` when dependency management is enabled.
4. Create source, binary, and configuration parent directories with one
`ansible.builtin.file` loop.
5. Check out `notarius_version` with `ansible.builtin.git`, `force: true`, and
register the module result.
6. Inspect whether `notarius_binary_path` exists with
`ansible.builtin.stat`.
7. Run the upstream Go build through `notarius_go_binary` when the checkout
changed or the binary is absent.
8. Converge recursive source ownership and binary ownership and mode with one
item-driven `ansible.builtin.file` loop.
9. Serialize `notarius_config` as YAML and manage `notarius_config_path` with
`ansible.builtin.copy`.
Apply task-level privilege escalation only where required. Use `argv` for the
build command and put its two conditions directly on the build task. Do not
add a rebuild fact, handler, handler flush, executable discovery, compiler or
version interrogation, configuration preflight, or post-operation validation
to production tasks.
## Rationale and Alternatives
Notarius has the same installation mechanics as the completed Seriatim and
Audita roles: declarative dependency and checkout management surrounding one
imperative build command. Binary existence is the only state probe Ansible
needs because it controls whether that command must run.
A single configuration mapping preserves Notarius's strict native schema and
avoids duplicating a large, evolving configuration surface as role variables.
The minimal valid document keeps the standalone role useful without embedding
D&D policy. The suite role can later provide the maintained pipeline,
PromptKit profile selection, concurrency, state paths, and other integrated
values as one complete override.
Managing `/usr/local/etc/notarius/config.yml` follows the application's own
configuration discovery contract and aligns locally installed software with
its configuration.
## Acceptance Criteria
- Unsupported distributions, Ubuntu releases, and architectures fail before
application state is modified.
- Default execution on the local Ubuntu 26.04 host installs or confirms Git
and Go and checks out tag `v0.6.0` at commit
`77ae132e5609916da40dcd4fcc749c000a63cbac`.
- The role builds with the fixed upstream contract and installs
`/usr/local/bin/notarius` as a regular file owned by `root:root` with mode
`0755`.
- The managed source checkout is recursively owned by `root:root`.
- The default schema-version 4 configuration is installed at
`/usr/local/etc/notarius/config.yml` as a regular file owned by `root:root`
with mode `0644`.
- Repository-local tests receive `notarius v0.6.0` from the installed CLI and
successfully validate the managed configuration.
- An immediate second role run reports no changes.
- A missing binary causes one rebuild followed by an unchanged run.
- A changed checkout causes one rebuild followed by an unchanged run.
- A configuration change updates only configuration state and does not rebuild
the binary.
- Dependency opt-out accepts a caller-supplied `notarius_go_binary`.
- A play connecting as an ordinary sudo-capable user can apply the role without
play-level privilege escalation.
- Defaults and argument specifications contain exactly the nine variables in
the Fixed Public Interface.
- Production tasks contain no CLI validation, fingerprints, checksums, sidecar
state, manual Git reset or clean commands, or probes before state already
managed by APT, Snap, `file`, `git`, or `copy`.
- Syntax checking, production-profile ansible-lint, focused local convergence,
CLI verification, configuration validation, and clean repeated runs pass.
- Role documentation describes actual behavior, dependency opt-out, the
complete configuration mapping, privilege use, and integration-test effects.
- No repository other than `ansible-role-notarius` and the workspace control
repository is modified.
## Dependencies and Follow-up Work
The managed host requires access to the Notarius Git repository, Ubuntu Snap
infrastructure, and Go module sources. Actual transcript processing also needs
a configured pipeline, input artifacts, PromptKit assets and endpoints, and
secret environment variables; those belong to consumers or later suite-level
work.
After this roadmap is approved, replace the pending notice at
`docs/roadmap/implementation.md` with a numbered staged Notarius implementation
plan. The pipeline role can select concrete `notarius_config` values after the
standalone interface is implemented and reviewed.
## Potential Future Hardening
- Build into a temporary path before replacing the installed executable.
- Verify source signatures or release checksums.
- Detect compiler, build-command, or out-of-band binary changes.
- Validate configuration during production convergence.
- Manage a dedicated runtime account, secret environment, state paths,
service, or schedule if later operating requirements select them.
- Add dedicated Ubuntu release and architecture test matrices.

View File

@@ -2,11 +2,11 @@
Status: pending
No implementation plan is currently active. Feature 0002 was completed in
`ansible-role-audita` through commit `3a8c21f`; its durable scope and rationale
remain in
No implementation plan is currently active. The Feature 0002 configuration
amendment was completed in `ansible-role-audita` commits `e61f02f` and
`847c4c3`. Its durable scope remains in
[the Feature 0002 roadmap](features/0002-audita-source-installation-and-configuration.md),
and its review history remains in [the remediation record](remediation.md).
Select and approve the next feature roadmap before replacing this notice with
a new staged implementation plan.
Feature 0003 is the next proposed unit of work. Review and approve its durable
roadmap before replacing this notice with a staged implementation plan.

View File

@@ -1,134 +1,40 @@
# Feature 0002 Remediation Review
# Feature 0002A Remediation Review
Status: resolved
The Audita production task flow implements the approved architecture and the
complete integration suite passes. The following residual issues should be
corrected before Feature 0002 is accepted.
The field-specific Audita configuration implementation has the intended
architecture and its complete integration suite passes.
## Finding 1: Correct the Declared Role License
Severity: medium
`ansible-role-audita/meta/main.yml` declares `BSD-3-Clause`, but the
repository's `LICENSE` file is CC0 1.0 Universal. Published role metadata must
identify the license actually granted by the repository.
### Required Remediation
- Change `galaxy_info.license` to the Galaxy-compatible SPDX identifier
`CC0-1.0`.
- Do not replace or otherwise alter the existing license text.
### Validation
- `meta/main.yml` and `LICENSE` identify the same license.
- Production-profile ansible-lint passes.
## Finding 2: Describe All Integration-Test Host Effects
## Finding 2: Synchronize Amendment Progress Tracking
Severity: low
`ansible-role-audita/README.md` says that the integration suite mutates only
the three Audita paths and its private temporary directory. Default
convergence also enables dependency management, so on a fresh supported host
the suite may install Git through APT, refresh the APT cache, and install the
Go Snap. The statement is therefore incomplete.
The configuration amendment was completed in `ansible-role-audita` commits
`e61f02f` and `847c4c3`, while the implementation plan and workspace status
still described it as awaiting execution.
### Required Remediation
### Resolution
- State that the suite may install or converge Git and the Go Snap in addition
to managing the listed Audita paths.
- Retain the statement that temporary test-specific files are confined to the
private temporary directory.
- Recorded the completed amendment commits in the durable Feature 0002
roadmap.
- Marked Feature 0002 complete in workspace status.
- Replaced the completed fixed-location implementation plan with a pending-plan
notice for Feature 0003.
- Preserved Feature 0003 as the next proposed unit of work and identified its
configuration-interface revision as the next roadmap-review step.
### Validation
## Review Conclusion
- The README accurately describes package/Snap effects and managed filesystem
paths.
- The description agrees with `tests/integration` and the role defaults.
No code remediation was required. A proposed assertion that the configuration
was a regular file was rejected because a successful
`ansible.builtin.template` operation already establishes the specified file
state. Adding another assertion would re-prove the module's documented
postcondition and conflict with the workspace convention to trust Ansible's
abstraction boundary.
## Finding 3: Complete Binary-Type Verification
Severity: low
`tests/verify.yml` checks binary ownership, mode, and executability, but does
not assert that `/usr/local/bin/audita` is a regular file. Stage 1 explicitly
requires baseline verification of binary type and metadata. The production
`file` task establishes this invariant, but the focused verification does not
provide the planned evidence for it.
### Required Remediation
- Add an assertion for `audita_binary_metadata.stat.isreg` to the existing
binary metadata check.
- Do not add another probe or production task.
### Validation
- `tests/verify.yml` confirms regular-file type, ownership, mode, and
executability from its existing `stat` result.
- The integration suite passes.
## Finding 4: Synchronize Implementation Progress Tracking
Severity: low
Both implementation stages are annotated complete in
`docs/roadmap/implementation.md`, at role commits `47f1852` and `d37f590`, but
the plan remains `ready`, its progress notes still say execution is ready to
begin, and `docs/status.md` still describes execution as the current activity.
The recorded state should show that implementation is complete and remediation
review is in progress.
The two workspace commits that added stage-completion annotations also diverge
from the plan's instruction that the out-of-band executor leave workspace
planning files unchanged. No implementation code was placed in the wrong
repository, so this requires tracking cleanup rather than code movement.
### Required Remediation
- Set the plan to `in_progress` while findings remain open and replace its
stale progress note with both completed stage commits and the current
remediation state.
- Update workspace status so Feature 0002 is `in_progress`, with implementation
complete and remediation pending, and make review/remediation the current
focus.
- Do not mark Feature 0002 `done` until remediation is implemented and
reviewed.
### Validation
- The plan's status, stage annotations, and progress notes describe one
consistent state.
- Workspace status agrees with the implementation and remediation records.
- `git diff --check` passes in the workspace repository.
## Review Validation Evidence
The review ran the complete `ansible-role-audita/tests/integration` suite on
Ubuntu 26.04 with Ansible Core 2.21.3 and ansible-lint 26.8.0. It passed syntax
checking, production-profile lint, baseline and repeated convergence,
missing-binary rebuilding, dependency opt-out with a caller-supplied Go
executable, metadata repair without rebuilding, configuration-only
convergence, alternate-checkout rebuilding, default restoration, native
configuration validation, and all three platform-rejection cases.
The final state was default commit
`a84941d68168a1ed9ea7423b6477ae8218be73f9`, a `root:root` mode `0755` binary,
a `root:root` mode `0644` configuration, and native validation output
`config is valid`. `bash -n tests/integration` and `git diff --check` also
passed. All nested repository working trees remained clean.
## Resolution
All four findings were implemented and validated on 2026-09-08. The role now
declares `CC0-1.0`, its README identifies dependency-management effects, and
its existing binary `stat` result proves regular-file type. Workspace tracking
records the completed and accepted feature. Role remediation was committed as
`3a8c21f`.
Validation passed with the complete `tests/integration` suite,
production-profile ansible-lint, `bash -n tests/integration`, and
`git diff --check` in both changed repositories. The production task flow was
not changed.
The review ran the complete `tests/integration` suite on Ubuntu 26.04 with
Ansible Core 2.21.3 and ansible-lint 26.8.0. It passed default minimal
rendering, representative nested rendering, explicit falsey values, native
configuration validation, configuration-only convergence, both rebuild
triggers, dependency opt-out, metadata repair, restored default state,
repeated convergence, and platform rejection. `git diff --check` also passed.