Compare commits
22 Commits
5713ce582e
...
a84a6383ec
| Author | SHA1 | Date | |
|---|---|---|---|
| a84a6383ec | |||
| 8e34f56f81 | |||
| e418edc5ef | |||
| e7607f45f7 | |||
| 7c2c9fe287 | |||
| 860651966a | |||
| 6034691350 | |||
| 8150dd2555 | |||
| bbeecc0055 | |||
| 77dcf8f7f7 | |||
| 3f20cf4b18 | |||
| 332bc4742b | |||
| 6d6b2307ff | |||
| ca82dd76aa | |||
| e4a307578c | |||
| 9ceaa2a5f1 | |||
| 1714b60dfe | |||
| 482e8473c2 | |||
| 4177b4de81 | |||
| f87962ca13 | |||
| 5dc879ecd7 | |||
| a3af153895 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,8 @@
|
||||
/ansible-role-scriptorium/
|
||||
/ansible-role-seriatim/
|
||||
/rakestraw-ansible/
|
||||
/assets/campaigns/
|
||||
/assets/narratio-prompts/
|
||||
|
||||
# Local tool state.
|
||||
/.codebase-memory/
|
||||
|
||||
12
AGENTS.md
12
AGENTS.md
@@ -12,9 +12,13 @@ is an independent Git repository.
|
||||
- Read [the workspace orientation](docs/orientation.md) before selecting,
|
||||
inspecting, or modifying a repository. It maps the repositories and defines
|
||||
the canonical sources of truth.
|
||||
- Read [the workspace conventions](docs/conventions.md) before reviewing or
|
||||
changing Ansible, preparing a feature roadmap or implementation plan, or
|
||||
making any repository change. It defines the normative house style and
|
||||
working conventions.
|
||||
- Read [the workspace conventions](docs/conventions.md) before making any
|
||||
repository change. They define the workspace-wide rules and route work to
|
||||
specialized policy.
|
||||
- Read [the Ansible house style](docs/ansible.md) before designing,
|
||||
implementing, or reviewing Ansible roles or collections, including plans
|
||||
that specify such work.
|
||||
- Read [the testing house style](docs/testing.md) before creating, changing,
|
||||
reviewing, or auditing tests, including plans that specify test work.
|
||||
- Read [the planning policy](docs/planning.md) before preparing a feature
|
||||
roadmap or implementation plan or managing an ongoing work stream.
|
||||
|
||||
@@ -7,8 +7,8 @@ only workspace documentation, planning, and shared development utilities.
|
||||
|
||||
## Start Here
|
||||
|
||||
- [`AGENTS.md`](AGENTS.md) describes repository boundaries and working
|
||||
conventions.
|
||||
- [`AGENTS.md`](AGENTS.md) describes repository boundaries and routes each
|
||||
kind of work to its required policy documents.
|
||||
- [`workspace.yml`](workspace.yml) inventories the repositories used during
|
||||
development.
|
||||
- [`docs/roadmap/mvp.md`](docs/roadmap/mvp.md) records settled MVP decisions
|
||||
|
||||
97
docs/ansible.md
Normal file
97
docs/ansible.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Ansible House Style
|
||||
|
||||
This policy is normative for designing, implementing, and reviewing Ansible
|
||||
roles and collections in this workspace.
|
||||
|
||||
## Role Implementation
|
||||
|
||||
- Always use the smallest clear sequence of declarative tasks that reaches the
|
||||
required end state.
|
||||
- Prefer `ansible.builtin` modules where they directly fit the task.
|
||||
`community.general` is an approved, stable dependency and its modules may be
|
||||
selected freely when appropriate; declare and pin the collection wherever a
|
||||
role or collection depends on it.
|
||||
- Do not strengthen the specification. Implement the requested invariants
|
||||
without inventing additional guarantees for integrity, provenance, drift
|
||||
recovery, corruption detection, rollback, or similar behavior.
|
||||
- Prefer convergence over state inspection. Declare what should be true and
|
||||
let the relevant module reconcile it.
|
||||
- Trust Ansible's abstraction boundary. A module that manages state owns the
|
||||
checks necessary to manage that state. Inspect it beforehand only when the
|
||||
observed state is independently required.
|
||||
- State inspection is justified when its result is necessary to decide whether
|
||||
an imperative operation must run, such as checking whether an arbitrary
|
||||
build command's output exists.
|
||||
- Production role tasks establish required application state; they do not test
|
||||
the role's own implementation. Put implementation verification in
|
||||
repository-local tests unless the specification explicitly requires runtime
|
||||
validation during convergence.
|
||||
- For an unavoidable `command` or `shell` task, declare the operation's change
|
||||
semantics as required by ansible-lint. A conditionally executed mutation may
|
||||
use `changed_when: true`; a read-only command should use
|
||||
`changed_when: false`. This describes an imperative operation and does not
|
||||
replace the idempotence of a state-management module.
|
||||
- Apply `become: true` to individual tasks that require elevated privileges.
|
||||
Do not require callers to escalate an entire play merely to use a role.
|
||||
- Complexity requires a requirement. Every additional task, conditional,
|
||||
registered variable, or state probe must correspond to behavior the role is
|
||||
required to provide.
|
||||
- Persisted role-private state is a design smell. Fingerprints, checksum
|
||||
databases, stamps, manifests, and similar bookkeeping require specific
|
||||
justification.
|
||||
- **Assume convergence first.** Before adding machinery for an edge case,
|
||||
determine whether rerunning the ordinary desired-state operations already
|
||||
repairs it.
|
||||
- Consider whether a conditional task or a notified handler best expresses the
|
||||
dependency. A `when` condition keeps triggers visible at the action site but
|
||||
grows with their number. Notifications keep the action independent of the
|
||||
number of notifiers, but distribute the control flow and defer execution
|
||||
until the next handler flush. An explicit
|
||||
`ansible.builtin.meta: flush_handlers` affects all pending handlers in the
|
||||
play.
|
||||
- Treat `rakestraw-ansible` as a style reference for direct tasks, shallow
|
||||
control flow, and concise variable use, while retaining current practices
|
||||
such as fully qualified collection names.
|
||||
|
||||
## Application Configuration Interfaces
|
||||
|
||||
- Expose application configuration through documented, field-specific role
|
||||
variables suitable for `host_vars`, `group_vars`, play variables, and
|
||||
composing roles.
|
||||
- Give structurally required fields concrete defaults. Define optional
|
||||
application settings as `null` unless the role intentionally owns the
|
||||
corresponding policy.
|
||||
- Treat a null optional variable as "omit this field from the rendered
|
||||
configuration." Do not copy documented upstream defaults into role defaults
|
||||
merely to write them back to the application.
|
||||
- Let the application supply its built-in defaults for omitted fields. This
|
||||
avoids freezing a duplicate defaults database in Ansible and permits upstream
|
||||
default changes to take effect naturally.
|
||||
- Use `is not none` when conditionally rendering optional values. Do not use
|
||||
truthiness, because false, zero, an empty string, or an empty collection may
|
||||
be an intentional value.
|
||||
- Emit a nested configuration section only when at least one of its descendant
|
||||
variables is non-null.
|
||||
- Serialize strings and collections with appropriate Ansible or Jinja filters.
|
||||
Do not construct YAML quoting manually.
|
||||
- Keep argument specifications aligned with the public variables. Optional
|
||||
nullable variables are not required; use a permissive type only when the
|
||||
native application accepts more than one scalar type.
|
||||
- Prefer one field-specific interface. Do not provide a parallel raw mapping,
|
||||
template override, or merge mechanism unless a concrete requirement defines
|
||||
its precedence and behavior.
|
||||
- Application roles expose native configuration choices. The suite-level role
|
||||
supplies cross-application and deployment-specific policy through those
|
||||
variables.
|
||||
- Manage the resulting file with one ordinary `ansible.builtin.template` task.
|
||||
Do not add configuration assembly facts, preliminary file inspection, or
|
||||
production validation unless independently required.
|
||||
- Configuration tests should use explicitly supplied representative values to
|
||||
exercise conditional rendering, null omission, intentional falsey values,
|
||||
native configuration validity, and caller-facing composition boundaries.
|
||||
They should follow [the testing house style](testing.md) rather than
|
||||
snapshotting the current default document.
|
||||
|
||||
Role defaults define what Ansible intends to manage, not a mirror of every
|
||||
application default. A concrete default means the role deliberately owns that
|
||||
policy; a null default leaves the policy with the application.
|
||||
@@ -1,6 +1,17 @@
|
||||
# Workspace Conventions
|
||||
|
||||
## Working Conventions
|
||||
These conventions apply to all work in this workspace. Read the specialized
|
||||
policy for the work being performed as well:
|
||||
|
||||
- Read [the Ansible house style](ansible.md) before designing, implementing,
|
||||
or reviewing Ansible roles or collections, including their configuration
|
||||
interfaces.
|
||||
- Read [the testing house style](testing.md) before creating, changing,
|
||||
reviewing, or auditing tests.
|
||||
- Read [the planning policy](planning.md) before preparing or managing a
|
||||
feature roadmap, implementation plan, or active work stream.
|
||||
|
||||
## Workspace-Wide Conventions
|
||||
|
||||
- Confirm the target repository before editing; never treat this directory as
|
||||
a monorepo.
|
||||
@@ -20,48 +31,3 @@
|
||||
run.
|
||||
- Do not duplicate an application contract in workspace documentation when a
|
||||
link and a concise deployment consequence are sufficient.
|
||||
|
||||
## Ansible House Style (Normative)
|
||||
|
||||
- Always use the smallest clear sequence of declarative tasks that reaches the
|
||||
required end state.
|
||||
- Prefer `ansible.builtin` modules where they directly fit the task.
|
||||
`community.general` is an approved, stable dependency and its modules may be
|
||||
selected freely when appropriate; declare and pin the collection wherever a
|
||||
role or collection depends on it.
|
||||
- Do not strengthen the specification. Implement the requested invariants
|
||||
without inventing additional guarantees for integrity, provenance, drift
|
||||
recovery, corruption detection, rollback, or similar behavior.
|
||||
- Prefer convergence over state inspection. Declare what should be true and
|
||||
let the relevant module reconcile it.
|
||||
- Trust Ansible's abstraction boundary. A module that manages state owns the
|
||||
checks necessary to manage that state. Inspect it beforehand only when the
|
||||
observed state is independently required.
|
||||
- State inspection is justified when its result is necessary to decide whether
|
||||
an imperative operation must run, such as checking whether an arbitrary
|
||||
build command's output exists.
|
||||
- Production role tasks establish required application state; they do not test
|
||||
the role's own implementation. Put implementation verification in
|
||||
repository-local tests unless the specification explicitly requires runtime
|
||||
validation during convergence.
|
||||
- Apply `become: true` to individual tasks that require elevated privileges.
|
||||
Do not require callers to escalate an entire play merely to use a role.
|
||||
- Complexity requires a requirement. Every additional task, conditional,
|
||||
registered variable, or state probe must correspond to behavior the role is
|
||||
required to provide.
|
||||
- Persisted role-private state is a design smell. Fingerprints, checksum
|
||||
databases, stamps, manifests, and similar bookkeeping require specific
|
||||
justification.
|
||||
- **Assume convergence first.** Before adding machinery for an edge case,
|
||||
determine whether rerunning the ordinary desired-state operations already
|
||||
repairs it.
|
||||
- Consider whether a conditional task or a notified handler best expresses the
|
||||
dependency. A `when` condition keeps triggers visible at the action site but
|
||||
grows with their number. Notifications keep the action independent of the
|
||||
number of notifiers, but distribute the control flow and defer execution
|
||||
until the next handler flush. An explicit
|
||||
`ansible.builtin.meta: flush_handlers` affects all pending handlers in the
|
||||
play.
|
||||
- Treat `rakestraw-ansible` as a style reference for direct tasks, shallow
|
||||
control flow, and concise variable use, while retaining current practices
|
||||
such as fully qualified collection names.
|
||||
|
||||
@@ -10,6 +10,10 @@ Repositories inside this directory:
|
||||
suite-level role exposed by the collection as `rakestraw.dnd.pipeline`.
|
||||
- `ansible-role-{narratio,notarius,audita,seriatim,scriptorium}`: standalone
|
||||
application roles.
|
||||
- `assets/campaigns`: D&D campaign registry content deployed by the pipeline
|
||||
role.
|
||||
- `assets/narratio-prompts`: PromptKit-compatible prompts and schemas deployed
|
||||
for Scriptorium by the pipeline role.
|
||||
- `rakestraw-ansible`: working deployment repository containing the
|
||||
`pipeline_dnd` proof of concept; treat it as read-only reference unless the
|
||||
task explicitly includes it.
|
||||
@@ -18,15 +22,17 @@ Relevant upstream repositories are siblings of this directory:
|
||||
|
||||
- `../{narratio,notarius,audita,seriatim,scriptorium}`: application source and
|
||||
authoritative application contracts.
|
||||
- `../narratio-prompts`: pipeline prompt-library content.
|
||||
|
||||
Use [the workspace inventory](../workspace.yml) as the complete
|
||||
machine-readable inventory of paths and remotes.
|
||||
|
||||
## Sources of Truth
|
||||
|
||||
- [Workspace conventions](conventions.md): normative working and Ansible house
|
||||
style.
|
||||
- [Workspace conventions](conventions.md): normative workspace-wide rules and
|
||||
policy routing.
|
||||
- [Ansible house style](ansible.md): normative role, collection, and
|
||||
application-configuration practices.
|
||||
- [Testing house style](testing.md): normative behavioral-testing practices.
|
||||
- [Planning policy](planning.md): normative feature planning and progress
|
||||
workflow.
|
||||
- [MVP roadmap](roadmap/mvp.md): settled MVP scope, architecture, and open
|
||||
@@ -41,4 +47,6 @@ machine-readable inventory of paths and remotes.
|
||||
active staged plan or, when no plan is approved, a pending-plan notice.
|
||||
- Application repositories: CLI, configuration, build, and integration
|
||||
contracts.
|
||||
- Asset repositories: authoritative campaign and prompt-library content and
|
||||
layout.
|
||||
- Individual Ansible repositories: implementation and repository-local tests.
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# Planning and Progress
|
||||
|
||||
- Read and follow [the workspace conventions](conventions.md) before preparing
|
||||
or revising any roadmap or implementation plan.
|
||||
or revising any roadmap or implementation plan. Also read the specialized
|
||||
policy applicable to the planned work: [the Ansible house style](ansible.md),
|
||||
[the testing house style](testing.md), or both.
|
||||
- Update [the MVP roadmap](roadmap/mvp.md) when a design question becomes a
|
||||
settled scope or architecture decision.
|
||||
- Discuss and select the next unit of work before planning implementation.
|
||||
@@ -28,7 +30,9 @@
|
||||
GPT-5.6-Terra to execute sequentially. Number stages with consecutive
|
||||
integers beginning with `Stage 1`; do not skip numbers or use nested stage
|
||||
numbering. Each stage must identify its repository, preconditions, required
|
||||
behavior, validation, completion criteria, and expected commit.
|
||||
policy reading, behavior, validation, completion criteria, and expected
|
||||
commit. Direct the implementing agent to reread the applicable policy
|
||||
documents immediately before beginning each stage.
|
||||
- Resolve architectural choices during roadmap and plan review. Do not leave
|
||||
unresolved design judgment to the implementation agent.
|
||||
- Update [workspace status](status.md) when cross-repository work starts,
|
||||
|
||||
@@ -37,7 +37,8 @@ the current design from becoming an accidental suite-wide pattern.
|
||||
it at `/usr/local/bin/seriatim`.
|
||||
- Rebuild when the source checkout changes or the binary is absent.
|
||||
- Converge the installed binary to `root:root` ownership and mode `0755`.
|
||||
- Verify the installed version in repository-local integration tests.
|
||||
- Verify an explicitly selected immutable Seriatim version through the native
|
||||
CLI in repository-local integration tests.
|
||||
- Keep the role interface, README, metadata, and focused local tests consistent
|
||||
with the simplified behavior.
|
||||
- Remove obsolete build-state files and implementation machinery from the
|
||||
@@ -213,7 +214,8 @@ used as templates for another role.
|
||||
- Detect arbitrary binary modification independently of reported version.
|
||||
- Protect or recover from unexpected symbolic links and malformed managed
|
||||
paths.
|
||||
- Add dedicated Ubuntu release and architecture test matrices.
|
||||
- Add broader Ubuntu release and architecture test coverage only if future
|
||||
platform behavior warrants it.
|
||||
|
||||
These are candidates for separately selected features if operational
|
||||
experience or a changed threat model justifies them.
|
||||
|
||||
@@ -6,243 +6,245 @@ 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 validate managed configurations through Audita. The
|
||||
current CLI has no native release-identity command, so the suite deliberately
|
||||
does not substitute a raw source-commit proxy for version coverage.
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
# Feature 0003: Notarius Source Installation and Configuration
|
||||
|
||||
Status: done
|
||||
|
||||
## 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
|
||||
|
||||
At feature selection, the `ansible-role-notarius` repository contained only
|
||||
its initial placeholder files. Notarius is one of the five required pipeline
|
||||
applications and needed an independently usable installation and
|
||||
native-configuration role before the suite role could 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.
|
||||
|
||||
## Governing Policies
|
||||
|
||||
- [The Ansible house style](../../ansible.md) governs the role implementation,
|
||||
its public configuration variables, and its template behavior.
|
||||
- [The testing house style](../../testing.md) governs repository-local
|
||||
validation. Tests exercise role-owned behavior through the public interface
|
||||
without snapshotting current defaults, tracing task implementation, or
|
||||
rechecking postconditions owned by trusted Ansible modules.
|
||||
|
||||
## 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.
|
||||
- Expose native configuration through field-specific role variables. Give the
|
||||
required schema version a concrete default and make every optional setting
|
||||
nullable so omitted settings remain owned by Notarius.
|
||||
- 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 raw mapping for the complete configuration document, a template override,
|
||||
or competing configuration interfaces.
|
||||
- Role defaults copied from Notarius merely to reproduce the application's
|
||||
built-in defaults in YAML.
|
||||
- Decomposing the open-ended `pipelines` map into role variables for every
|
||||
possible pipeline, step, lane, binding, validator, option, or reference.
|
||||
- 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`.
|
||||
|
||||
When a caller sets an optional configuration variable, the corresponding
|
||||
native field appears in the correct YAML section. Null fields are absent, as
|
||||
are parent sections with no selected descendants. Explicit false, zero, empty
|
||||
string, empty collection, and other non-null values are rendered and left to
|
||||
Notarius's native validation. `notarius_pipelines` represents the native
|
||||
open-ended `pipelines` field as one mapping rather than attempting to mirror
|
||||
its extensible internal schema in Ansible variables. Callers may define
|
||||
pipeline-map fragments in separate inventory files and compose them into the
|
||||
final value with ordinary Ansible/Jinja expressions.
|
||||
|
||||
An immediate second application reports no changes. A changed Git checkout or
|
||||
missing binary causes one build; configuration changes converge independently
|
||||
through the ordinary `ansible.builtin.template` operation.
|
||||
|
||||
Repository-local tests exercise the real role through its public variables.
|
||||
They use the default invocation only as a smoke test, explicitly select
|
||||
immutable `v0.5.0` to prove version selection, exercise missing-binary recovery
|
||||
with a caller-supplied Go executable, and render one representative
|
||||
configuration covering null omission, intentional falsey values, and
|
||||
caller-side pipeline composition. Application-native commands verify the
|
||||
selected release and configuration validity, and immediate repeated
|
||||
applications verify convergence.
|
||||
|
||||
## 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 field-specific variables.
|
||||
- `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_version` names the schema version so `notarius_version`
|
||||
remains unambiguously the selected application release.
|
||||
- Optional configuration variables are declared with YAML null defaults.
|
||||
Template conditions use `is not none`, and parent mappings are emitted only
|
||||
when at least one descendant is non-null.
|
||||
- The native `pipelines` field is exposed as the nullable
|
||||
`notarius_pipelines` mapping. It is one field-specific variable, not a raw
|
||||
mapping for the complete document; the role serializes its value without
|
||||
defining a parallel schema for pipeline internals.
|
||||
- Pipeline composition belongs to the caller. For example, inventory may
|
||||
define `notarius_pipeline_group_one` and `notarius_pipeline_group_two` as
|
||||
mappings and set `notarius_pipelines` to
|
||||
`{{ notarius_pipeline_group_one | combine(notarius_pipeline_group_two) }}`.
|
||||
The role accepts and renders the resulting mapping without its own merge or
|
||||
precedence mechanism.
|
||||
- Strings and mappings are serialized with Ansible or Jinja filters rather
|
||||
than hand-written YAML quoting.
|
||||
- `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 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` remains buildable with the same Go requirement, package, linker
|
||||
symbol, and configuration schema and is the explicit immutable release used
|
||||
for focused native version-selection coverage.
|
||||
|
||||
## Fixed Public Interface
|
||||
|
||||
Provide these installation variables:
|
||||
|
||||
| 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 |
|
||||
|
||||
Provide these configuration variables:
|
||||
|
||||
| Variable | Default | Native field |
|
||||
| --- | --- | --- |
|
||||
| `notarius_config_version` | `4` | `version` |
|
||||
| `notarius_promptkit_profile_dir` | `null` | `promptkit.profile_dir` |
|
||||
| `notarius_promptkit_profile_file` | `null` | `promptkit.profile_file` |
|
||||
| `notarius_promptkit_local_backend_endpoint` | `null` | `promptkit.local_backend.endpoint` |
|
||||
| `notarius_promptkit_local_backend_concurrency_limit` | `null` | `promptkit.local_backend.concurrency_limit` |
|
||||
| `notarius_pipelines` | `null` | `pipelines` |
|
||||
| `notarius_concurrency_total_llm` | `null` | `concurrency.total_llm` |
|
||||
| `notarius_concurrency_stage_workers_extract` | `null` | `concurrency.stage_workers.extract` |
|
||||
| `notarius_output_directory` | `null` | `output.directory` |
|
||||
| `notarius_cache_chunk_plans_mode` | `null` | `cache.chunk_plans.mode` |
|
||||
| `notarius_cache_chunk_plans_directory` | `null` | `cache.chunk_plans.directory` |
|
||||
| `notarius_cache_checkpoints_enabled` | `null` | `cache.checkpoints.enabled` |
|
||||
| `notarius_cache_checkpoints_directory` | `null` | `cache.checkpoints.directory` |
|
||||
| `notarius_debug_directory` | `null` | `debug.directory` |
|
||||
|
||||
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.
|
||||
|
||||
Argument specifications type each value according to its native shape. The
|
||||
role does not reproduce semantic relationships such as the mutual exclusion
|
||||
of PromptKit profile sources or the requirement for a local-backend endpoint;
|
||||
Notarius owns those constraints. The `notarius_pipelines` value is a mapping
|
||||
whose nested structure is governed by Notarius's versioned configuration
|
||||
contract.
|
||||
|
||||
## 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. Render the field-specific configuration with one
|
||||
`ansible.builtin.template` task, conditionally emitting optional fields and
|
||||
parent sections at `notarius_config_path`.
|
||||
|
||||
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 assembly facts, preliminary
|
||||
configuration probes, 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.
|
||||
|
||||
Field-specific variables are the ordinary ergonomic interface for inventory
|
||||
and composing roles. Nullable defaults expose and type that interface without
|
||||
freezing Notarius's built-in defaults into Ansible. Conditional rendering
|
||||
preserves the distinction between omission and an intentionally falsey value.
|
||||
|
||||
The pipeline definitions are the deliberate exception to leaf-level
|
||||
variables. `pipelines` is itself an open-ended map whose nested keys depend on
|
||||
registered modules and evolve with the application's native schema. Exposing
|
||||
that native field as one nullable mapping keeps the interface practical while
|
||||
still avoiding a raw complete-document mapping or merge semantics. The suite
|
||||
role can later supply its maintained D&D pipeline through
|
||||
`notarius_pipelines` and supply operating policy through the other variables.
|
||||
|
||||
This boundary also supports modular inventory. A consumer can keep one or
|
||||
more pipeline mappings in separate `host_vars`, `group_vars`, or included
|
||||
variable files and combine them when assigning `notarius_pipelines`. Because
|
||||
the native value is a mapping keyed by pipeline ID, dictionary composition
|
||||
uses Ansible's `combine` filter; list concatenation with `+` applies only to
|
||||
list-valued data. The role receives the already composed native mapping and
|
||||
does not need custom loading, merging, or precedence behavior.
|
||||
|
||||
Leaving optional variables undefined would produce the same minimal file but
|
||||
would weaken interface documentation and argument validation. Section-level
|
||||
dictionaries would be less ergonomic for ordinary inventory values. A raw
|
||||
complete configuration mapping would force consumers to replace the required
|
||||
version and unrelated sections together and would conflict with the workspace
|
||||
convention of one field-specific interface.
|
||||
|
||||
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
|
||||
|
||||
### Required Role Behavior
|
||||
|
||||
- The role rejects unsupported distributions, Ubuntu releases, and
|
||||
architectures before modifying application state.
|
||||
- On a supported host, the role installs the selected Notarius source release
|
||||
with its upstream build contract. The default selection for this feature is
|
||||
tag `v0.6.0`, resolving to commit
|
||||
`77ae132e5609916da40dcd4fcc749c000a63cbac`.
|
||||
- The role converges the source tree, binary, and configuration to the paths,
|
||||
ownership, and modes defined above using the responsible Ansible modules.
|
||||
- The default template renders the minimal valid configuration containing the
|
||||
required schema version and leaves optional policy to Notarius.
|
||||
- A non-null optional variable renders its corresponding native field. Null
|
||||
values and parent sections without a selected descendant are omitted;
|
||||
intentional falsey values are preserved.
|
||||
- Independently defined inventory mappings can be combined into
|
||||
`notarius_pipelines`, and the resulting pipeline IDs and definitions are
|
||||
rendered without structural rewriting by the role.
|
||||
- A changed checkout or missing binary causes the imperative build to run. An
|
||||
immediate repeated application with unchanged inputs reports no changes.
|
||||
- Dependency opt-out accepts a caller-supplied `notarius_go_binary`.
|
||||
- Tasks requiring elevated access use task-level privilege escalation, so the
|
||||
role does not require play-level escalation.
|
||||
- Defaults, argument specifications, template behavior, and documentation
|
||||
remain aligned with the public interface without introducing a parallel raw
|
||||
configuration or template-override interface.
|
||||
- Production tasks contain no role-private build state, redundant probes,
|
||||
application self-tests, or other behavior outside the selected invariants.
|
||||
- No repository other than `ansible-role-notarius` and the workspace control
|
||||
repository is modified.
|
||||
|
||||
### Required Validation
|
||||
|
||||
- Syntax checking and production-profile ansible-lint pass.
|
||||
- A default invocation provides a smoke test through the installed CLI and
|
||||
native configuration validator, followed immediately by a role application
|
||||
reporting no changes. The test does not assert that the role's current
|
||||
default release or complete default document remains unchanged.
|
||||
- A focused version-selection case explicitly requests immutable tag `v0.5.0`
|
||||
and verifies that the installed CLI reports `notarius v0.5.0`.
|
||||
- One recovery case removes the binary, disables dependency management,
|
||||
supplies a caller-selected Go executable, confirms that executable is used,
|
||||
and finishes with a clean repeated application.
|
||||
- One representative configuration case verifies selected rendered values,
|
||||
selected omissions, intentional falsey values, and caller-side composition
|
||||
of two pipeline mappings. The native Notarius validator accepts the result,
|
||||
and an immediate repeated application reports no changes.
|
||||
- Tests do not assert task names or order, individual task results, exact
|
||||
current defaults, complete configuration snapshots, public-variable counts,
|
||||
trusted-module file or package postconditions, or an exhaustive negative
|
||||
platform matrix.
|
||||
|
||||
## 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.
|
||||
|
||||
The role was implemented in `ansible-role-notarius` commits `287fc4a` and
|
||||
`733a194`, then finalized by remediation commit `eb4f511`. Its complete
|
||||
integration suite passes. The pipeline role can now supply its D&D definitions
|
||||
through `notarius_pipelines` and select the other field-specific values.
|
||||
|
||||
## 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 broader Ubuntu release and architecture test coverage only if future
|
||||
platform behavior warrants it.
|
||||
@@ -0,0 +1,335 @@
|
||||
# Feature 0004: Scriptorium Source Installation and Configuration
|
||||
|
||||
Status: done
|
||||
|
||||
## Summary
|
||||
|
||||
Provide a small, independently usable `rakestraw.scriptorium` role that
|
||||
installs Scriptorium from a pinned Git tag, builds its executable on the
|
||||
managed host, and manages its native YAML configuration. Preserve
|
||||
Scriptorium's usefulness inside and outside the D&D transcript pipeline by
|
||||
keeping application configuration in the standalone role and leaving prompt
|
||||
library content and suite policy to their eventual owners.
|
||||
|
||||
## Problem or Opportunity
|
||||
|
||||
The `ansible-role-scriptorium` repository contains only its initial README and
|
||||
license. Scriptorium is one of the five applications required by the pipeline,
|
||||
but it is also a generally useful Promptkit-based application with independent
|
||||
consumers. It needs a complete standalone installation and configuration role
|
||||
before the pipeline role can compose it without owning Scriptorium-specific
|
||||
behavior.
|
||||
|
||||
The completed Seriatim, Audita, and Notarius roles establish the concise
|
||||
source-build pattern. Scriptorium can reuse that pattern while exposing its own
|
||||
configuration contract through field-specific, nullable variables.
|
||||
|
||||
## Governing Policies
|
||||
|
||||
- [The Ansible house style](../../ansible.md) governs the role implementation,
|
||||
public configuration interface, and template.
|
||||
- [The testing house style](../../testing.md) governs repository-local
|
||||
validation. Tests exercise role-owned behavior through public inputs and
|
||||
native application outcomes without snapshotting defaults, tracing tasks, or
|
||||
rechecking trusted-module postconditions.
|
||||
- [The MVP roadmap](../mvp.md) fixes the common source-build architecture,
|
||||
supported platform, filesystem layout, and standalone-role boundary.
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement `ansible-role-scriptorium` 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 Scriptorium tag `v0.13.0` by default under
|
||||
`/usr/local/src/scriptorium`.
|
||||
- Build the native executable with Scriptorium's release build contract and
|
||||
install it at `/usr/local/bin/scriptorium`.
|
||||
- Rebuild when the Git checkout changes or the binary is absent.
|
||||
- Converge the source tree to `root:root` ownership and the installed binary to
|
||||
`root:root` ownership and mode `0755`.
|
||||
- Manage `/usr/local/etc/scriptorium/config.yml` as `root:root` with mode
|
||||
`0644` using one role-owned template.
|
||||
- Render `{}` when no application settings are selected, allowing Scriptorium
|
||||
to use its built-in defaults without copying them into Ansible.
|
||||
- Expose every application configuration field through a field-specific role
|
||||
variable. Default each field to null and omit it from the rendered document
|
||||
until a caller supplies a non-null value.
|
||||
- Expose the native open-ended `backends` mapping as one nullable variable and
|
||||
serialize the caller's mapping without inventing a second backend schema or
|
||||
merge mechanism.
|
||||
- Keep defaults, argument specifications, README, metadata, collection
|
||||
dependency declaration, template, and focused integration tests aligned with
|
||||
this contract.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- D&D-specific prompts, profiles, schemas, model choices, paths, or other
|
||||
pipeline policy.
|
||||
- Cloning, copying, or otherwise populating prompt, profile, or schema
|
||||
libraries.
|
||||
- A role-managed Scriptorium service, HTTP listener lifecycle, scheduler, or
|
||||
persistent runtime account.
|
||||
- A raw mapping for the complete configuration document, a template override,
|
||||
or parallel configuration interfaces.
|
||||
- Copying Scriptorium's documented built-in defaults into role defaults merely
|
||||
to render them back into YAML.
|
||||
- Decomposing the open-ended `backends` mapping into variables for each backend
|
||||
ID or backend-specific option.
|
||||
- Secret values, environment files, or another credential-delivery mechanism.
|
||||
- Installation or configuration of Promptkit, another pipeline application,
|
||||
or the complete D&D suite.
|
||||
- Installation from Scriptorium's published binary artifacts, cross-compiling,
|
||||
or supporting platforms outside the MVP.
|
||||
- Production execution of Scriptorium to validate its binary 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.
|
||||
|
||||
## Target End State
|
||||
|
||||
On a supported host, applying the role with defaults installs or confirms Git
|
||||
and Go, checks out Scriptorium `v0.13.0` at
|
||||
`/usr/local/src/scriptorium`, builds `/usr/local/bin/scriptorium`, and manages
|
||||
`/usr/local/etc/scriptorium/config.yml`. The managed configuration is the empty
|
||||
mapping `{}`, so Scriptorium retains ownership of all application defaults.
|
||||
|
||||
When a caller sets an optional configuration variable, the corresponding
|
||||
native YAML field appears in the correct section. Null fields are absent, as
|
||||
are parent mappings with no selected descendants. Explicit false, zero, empty
|
||||
string, empty collection, and other non-null values are serialized rather than
|
||||
silently omitted, leaving their native semantics to Scriptorium.
|
||||
`scriptorium_backends` represents the complete native `backends` field as a
|
||||
mapping keyed by backend ID; the role does not rewrite its nested definitions
|
||||
or combine fragments. Callers and composing roles may construct the final
|
||||
mapping with ordinary inventory and Jinja expressions.
|
||||
|
||||
Prompt, profile, and schema directories remain caller-provided application
|
||||
inputs. The standalone role exposes their configuration paths but does not
|
||||
populate them. A later pipeline feature will deploy the maintained prompt
|
||||
library and pass its selected locations through this public interface.
|
||||
|
||||
An immediate repeated application reports no changes. A changed checkout or a
|
||||
missing binary causes the build command to run. Configuration changes converge
|
||||
through the template without becoming build triggers.
|
||||
|
||||
## Repository Ownership
|
||||
|
||||
- `ansible-role-scriptorium` owns the role implementation, public variables,
|
||||
native configuration serialization, metadata, dependency declaration,
|
||||
documentation, and repository-local tests.
|
||||
- `../scriptorium` is the read-only authority for release, build, CLI, and
|
||||
configuration contracts.
|
||||
- `rakestraw-ansible` is a read-only style and historical deployment reference.
|
||||
- `ansible-role-dnd-pipeline` will later own D&D-specific Scriptorium values and
|
||||
prompt-library deployment through the standalone role's public interface.
|
||||
- `ansible-workspace-dnd` owns this roadmap, the eventual staged implementation
|
||||
plan, and aggregate status.
|
||||
- All other repositories remain unchanged.
|
||||
|
||||
## Constraints and Settled Decisions
|
||||
|
||||
- The selected default release is annotated tag `v0.13.0`, resolving to commit
|
||||
`f33af205242cbaeeb689c179c0465bd10beaa1a3`.
|
||||
- The release declares Go 1.25.5. The suite-standard `1.26/stable` Go Snap
|
||||
channel satisfies that requirement.
|
||||
- The native build uses package `./cmd/scriptorium`, `CGO_ENABLED=0`,
|
||||
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags `-s -w`.
|
||||
- Scriptorium does not embed the selected application tag and does not expose a
|
||||
native application-version command. Production convergence does not add
|
||||
version interrogation, and tests do not inspect the Git checkout merely to
|
||||
manufacture version evidence.
|
||||
- Scriptorium accepts an empty configuration and resolves all omitted settings
|
||||
from built-in defaults. The role renders `{}` so the managed file is an
|
||||
explicit YAML mapping while selecting no application policy.
|
||||
- Configuration discovery checks `/usr/local/etc/scriptorium/config.yml`
|
||||
before `/etc/scriptorium/config.yml`; the role manages the first path.
|
||||
- Optional variables use YAML null defaults and template conditions use
|
||||
`is not none`. Parent mappings are emitted only when at least one descendant
|
||||
is non-null.
|
||||
- Strings and mappings are serialized with Ansible or Jinja filters rather
|
||||
than hand-written YAML quoting.
|
||||
- `scriptorium_backends` is a native open-ended mapping. Caller-side mapping
|
||||
composition is permitted, but the role supplies no merge or precedence
|
||||
behavior.
|
||||
- Backend configuration may name a credential environment variable through
|
||||
`api_key_env`; secret values themselves remain outside the role and managed
|
||||
file.
|
||||
- Tasks installing dependencies or managing 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.
|
||||
|
||||
## Fixed Public Interface
|
||||
|
||||
Provide these installation variables:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `scriptorium_version` | `v0.13.0` | Selected Git revision |
|
||||
| `scriptorium_repository_url` | `https://gitea.maximumdirect.net/eric/scriptorium.git` | Source repository |
|
||||
| `scriptorium_source_dir` | `/usr/local/src/scriptorium` | Managed source checkout |
|
||||
| `scriptorium_binary_path` | `/usr/local/bin/scriptorium` | Installed executable |
|
||||
| `scriptorium_manage_build_dependencies` | `true` | Whether to install Git and Go |
|
||||
| `scriptorium_go_snap_channel` | `1.26/stable` | Go Snap channel |
|
||||
| `scriptorium_go_binary` | `/snap/bin/go` | Go executable used for the build |
|
||||
| `scriptorium_config_path` | `/usr/local/etc/scriptorium/config.yml` | Managed configuration file |
|
||||
|
||||
Provide these nullable configuration variables:
|
||||
|
||||
| Variable | Native field |
|
||||
| --- | --- |
|
||||
| `scriptorium_prompt_dir` | `prompt_dir` |
|
||||
| `scriptorium_profile_dir` | `profile_dir` |
|
||||
| `scriptorium_schema_dir` | `schema_dir` |
|
||||
| `scriptorium_server_addr` | `server.addr` |
|
||||
| `scriptorium_server_artifact_root` | `server.artifact_root` |
|
||||
| `scriptorium_server_max_request_bytes` | `server.max_request_bytes` |
|
||||
| `scriptorium_server_max_artifact_bytes` | `server.max_artifact_bytes` |
|
||||
| `scriptorium_server_max_response_bytes` | `server.max_response_bytes` |
|
||||
| `scriptorium_defaults_render_format` | `defaults.render_format` |
|
||||
| `scriptorium_backends` | `backends` |
|
||||
|
||||
Argument specifications type paths and strings according to their native
|
||||
shape, the three server limits as integers, and `scriptorium_backends` as a
|
||||
mapping. They do not reproduce semantic validation owned by Scriptorium. The
|
||||
role preserves non-null values while the application decides whether a
|
||||
selected value is valid or effective.
|
||||
|
||||
## Simplest Viable Implementation
|
||||
|
||||
The expected production 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 `scriptorium_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 `scriptorium_version` with `ansible.builtin.git`, `force: true`,
|
||||
and register the module result.
|
||||
6. Inspect whether `scriptorium_binary_path` exists with
|
||||
`ansible.builtin.stat`.
|
||||
7. Run the native Go build through `scriptorium_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. Render the field-specific configuration with one
|
||||
`ansible.builtin.template` task.
|
||||
|
||||
Use `argv` for the build command, declare its change semantics, and put its two
|
||||
conditions directly on the task. Do not add a rebuild fact, handler, executable
|
||||
discovery, compiler or application interrogation, configuration assembly facts,
|
||||
preliminary configuration probes, or post-operation validation to production
|
||||
tasks.
|
||||
|
||||
## Rationale and Alternatives
|
||||
|
||||
A standalone role is valuable beyond the D&D pipeline and prevents the suite
|
||||
role from becoming the owner of Scriptorium's native application interface.
|
||||
The suite can later provide opinionated directory paths and backend choices
|
||||
without reducing the role's usefulness to independent consumers.
|
||||
|
||||
Field-specific nullable variables preserve a documented and typed inventory
|
||||
interface while allowing upstream defaults to evolve. Rendering `{}` is
|
||||
preferable to copying those defaults into Ansible and is more explicit than an
|
||||
empty file. Conditional sections distinguish omission from intentional falsey
|
||||
values.
|
||||
|
||||
The `backends` mapping is the deliberate exception to leaf-level variables.
|
||||
Its keys are caller-defined backend IDs and its values follow an extensible
|
||||
native schema. Passing that one native field through as a mapping is simpler
|
||||
and more useful than inventing variables for arbitrary IDs, while still
|
||||
avoiding a raw mapping for the complete configuration document.
|
||||
|
||||
The role exposes server configuration because it is part of Scriptorium's
|
||||
native interface, but it does not infer that callers want a managed service.
|
||||
Consumers may invoke the CLI directly or arrange their own process lifecycle.
|
||||
|
||||
Scriptorium now publishes binary release artifacts, but the MVP deliberately
|
||||
uses the common source-build model across all five applications. Artifact-based
|
||||
installation remains a later cross-suite decision.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### Required Role Behavior
|
||||
|
||||
- The role rejects unsupported platforms before modifying application state.
|
||||
- On a supported host, it installs the selected Scriptorium source release and
|
||||
builds the binary with the upstream release contract.
|
||||
- Source, binary, and configuration state converge to the paths, ownership,
|
||||
and modes selected above through the responsible Ansible modules.
|
||||
- With no configuration variables selected, the template renders `{}` and
|
||||
Scriptorium accepts the managed file while retaining its built-in defaults.
|
||||
- Each non-null configuration variable renders its corresponding native field.
|
||||
Null fields and empty parent sections are omitted, while intentional falsey
|
||||
values are retained.
|
||||
- A caller-supplied backend mapping is rendered without structural rewriting,
|
||||
and independently defined mappings can be composed before assignment.
|
||||
- A changed checkout or missing binary causes the imperative build to run. An
|
||||
immediate repeated application with unchanged inputs reports no changes.
|
||||
- Dependency opt-out accepts a caller-supplied `scriptorium_go_binary`.
|
||||
- Root-owned operations use task-level privilege escalation; play-level
|
||||
escalation is not required.
|
||||
- Defaults, argument specifications, template behavior, README, and metadata
|
||||
remain aligned with the public interface.
|
||||
- Production tasks contain no role-private state, redundant probes,
|
||||
application self-tests, or speculative guarantees.
|
||||
- No repository other than `ansible-role-scriptorium` and the workspace control
|
||||
repository is modified.
|
||||
|
||||
### Required Validation
|
||||
|
||||
- Syntax checking and production-profile ansible-lint pass.
|
||||
- A default invocation exercises the installed application with the managed
|
||||
configuration, followed immediately by a role application reporting no
|
||||
changes. It does not snapshot the role's current default tag or complete
|
||||
default document.
|
||||
- One recovery case removes the binary, disables dependency management,
|
||||
supplies a caller-selected Go executable, confirms that executable is used,
|
||||
and finishes with a clean repeated application.
|
||||
- One representative configuration case verifies selected scalar and nested
|
||||
values, selected omissions, intentional zero values, and a caller-supplied
|
||||
backend mapping. An offline native Scriptorium command accepts and uses the
|
||||
managed configuration, and an immediate repeated application reports no
|
||||
changes.
|
||||
- Tests do not assert task names or order, individual task results, exact
|
||||
current defaults, complete configuration snapshots, public-variable counts,
|
||||
trusted-module file or package postconditions, or an exhaustive negative
|
||||
platform matrix.
|
||||
- Because Scriptorium exposes no native application release identity, the test
|
||||
suite does not substitute a Git-checkout assertion or version-specific
|
||||
behavior snapshot for a native version-selection test.
|
||||
|
||||
## Dependencies and Follow-up Work
|
||||
|
||||
The managed host requires access to the Scriptorium Git repository, Ubuntu
|
||||
Snap infrastructure, and Go module sources. Useful prompt execution also needs
|
||||
prompt definitions and, depending on the chosen configuration, profiles,
|
||||
schemas, backend endpoints, and credential environment variables. Those inputs
|
||||
remain caller responsibilities for this standalone feature.
|
||||
|
||||
With this feature complete, the Narratio standalone role can be designed
|
||||
against all four downstream application-role interfaces. The later pipeline
|
||||
role will install maintained prompt-library content and supply D&D-specific
|
||||
Scriptorium configuration through this role.
|
||||
|
||||
The role was implemented in `ansible-role-scriptorium` commits `90d7f45` and
|
||||
`5944eac`, then finalized after independent review by remediation commit
|
||||
`8f47aa8`. Its complete integration suite passes.
|
||||
|
||||
## Potential Future Hardening
|
||||
|
||||
- Build into a temporary path before replacing the installed executable.
|
||||
- Verify source signatures or release artifacts.
|
||||
- Detect compiler, build-command, or out-of-band binary changes.
|
||||
- Validate configuration during production convergence.
|
||||
- Manage a service, runtime account, secret environment, or network controls if
|
||||
later operating requirements select them.
|
||||
- Support Scriptorium's published binary artifacts as part of a future
|
||||
suite-wide installation-model change.
|
||||
- Add broader platform coverage only when supported-platform behavior expands.
|
||||
@@ -0,0 +1,465 @@
|
||||
# Feature 0005: Narratio Source Installation and Configuration
|
||||
|
||||
Status: done
|
||||
|
||||
## Summary
|
||||
|
||||
Provide a small, independently usable `rakestraw.narratio` role that installs
|
||||
Narratio from a pinned Git tag, builds its executable on the managed host,
|
||||
creates the application account and runtime directories, and manages its
|
||||
native pipeline configuration. Keep the role application-specific so the
|
||||
later suite role can supply D&D policy through its public interface without
|
||||
making the Narratio role responsible for the other applications or campaign
|
||||
content.
|
||||
|
||||
## Problem or Opportunity
|
||||
|
||||
The `ansible-role-narratio` repository contains only its initial README and
|
||||
license. Narratio is the command-line orchestrator for the transcript pipeline,
|
||||
so the complete suite cannot be composed until Narratio has an independently
|
||||
usable installation and configuration role.
|
||||
|
||||
The four completed downstream application roles establish the concise
|
||||
source-build pattern. Narratio can reuse that pattern, but its native contract
|
||||
also requires a deployment account, shared writable runtime areas, a campaign
|
||||
registry root, and a substantially larger pipeline configuration interface.
|
||||
This feature fixes those boundaries before suite composition begins.
|
||||
|
||||
## Governing Policies
|
||||
|
||||
- [The Ansible house style](../../ansible.md) governs the role implementation,
|
||||
public configuration interface, and template.
|
||||
- [The testing house style](../../testing.md) governs repository-local
|
||||
validation. Tests exercise role-owned behavior through public inputs and
|
||||
native application outcomes without snapshotting defaults, tracing tasks, or
|
||||
rechecking trusted-module postconditions.
|
||||
- [The MVP roadmap](../mvp.md) fixes the common source-build architecture,
|
||||
supported platform, filesystem layout, and standalone-role boundary.
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement `ansible-role-narratio` 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 Narratio tag `v2.0.0` by default under
|
||||
`/usr/local/src/narratio`.
|
||||
- Build the native executable with Narratio's release build contract and
|
||||
install it at `/usr/local/bin/narratio`.
|
||||
- Rebuild when the Git checkout changes or the binary is absent.
|
||||
- Converge the source tree and installed binary to root ownership, with the
|
||||
binary at mode `0755`.
|
||||
- Create the `narratio` system group and system account with
|
||||
`/var/lib/narratio` as its home and a non-login shell.
|
||||
- Create the workspace, spool, and cache roots as group-writable,
|
||||
setgid directories owned by `narratio:narratio`.
|
||||
- Create the campaign registry as a root-managed, operator-readable content
|
||||
root; leave its contents to the suite role or another caller.
|
||||
- Manage `/usr/local/etc/narratio/pipeline.yml` as `root:narratio` with mode
|
||||
`0640` using one role-owned template.
|
||||
- Require the caller to supply the deployment-specific WhisperX transcription
|
||||
URL because Narratio has no valid universal value for this required field.
|
||||
- Give filesystem roots concrete role-owned defaults. Default other optional
|
||||
application settings to null and omit them until a caller supplies a
|
||||
non-null value, allowing Narratio to retain ownership of its built-in
|
||||
defaults.
|
||||
- Expose scalar fields individually. Expose native open-ended collections as
|
||||
one variable each, including publish outputs, Notarius references and
|
||||
outputs, and Scriptorium artifacts and artifact families.
|
||||
- Permit callers to compose those collection variables in inventory before
|
||||
assigning the final value; do not add role-owned merge or precedence logic.
|
||||
- Expose ConfigKit's explicit import list in the root document without taking
|
||||
ownership of the imported fragments or named profile overlays.
|
||||
- Keep defaults, argument specifications, README, metadata, collection
|
||||
dependency declaration, template, and focused integration tests aligned
|
||||
with this contract.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Installing or configuring Audita, Notarius, Seriatim, Scriptorium, WhisperX,
|
||||
or the complete D&D suite.
|
||||
- Populating campaign data, prompt libraries, profiles, schemas, or session
|
||||
documents.
|
||||
- Selecting D&D-specific pipelines, campaigns, models, prompts, artifacts,
|
||||
extraction lanes, publish rules, storage providers, or application paths.
|
||||
- Managing ConfigKit import fragments or named profile overlay files.
|
||||
- Managing credentials, secret values, a secrets directory, environment
|
||||
injection, or the pipeline-wide secret-delivery policy.
|
||||
- Adding human operator accounts to the `narratio` group; the suite role owns
|
||||
operator selection and membership.
|
||||
- A Narratio daemon, service unit, scheduler, or timer.
|
||||
- A raw mapping for the complete pipeline document, a template override, or a
|
||||
second parallel configuration interface.
|
||||
- Copying Narratio's built-in defaults into role defaults merely to render
|
||||
them back into YAML.
|
||||
- Decomposing open-ended artifact, artifact-family, reference, or output maps
|
||||
into variables for caller-defined keys.
|
||||
- Installing from published binary artifacts, cross-compiling, or supporting
|
||||
platforms outside the MVP.
|
||||
- Production execution of Narratio to validate its binary 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.
|
||||
|
||||
## Target End State
|
||||
|
||||
On a supported host, applying the role with the required
|
||||
`narratio_whisperx_transcribe_url` installs or confirms Git and Go, creates the
|
||||
Narratio account and filesystem roots, checks out Narratio `v2.0.0` at
|
||||
`/usr/local/src/narratio`, builds `/usr/local/bin/narratio`, and manages
|
||||
`/usr/local/etc/narratio/pipeline.yml`.
|
||||
|
||||
The baseline managed pipeline document contains only the caller's required
|
||||
WhisperX URL and the filesystem roots the role deliberately owns. Narratio
|
||||
continues to supply all other application defaults. When a caller sets an
|
||||
optional configuration variable, the corresponding native YAML field appears
|
||||
in the correct section. Null fields and parent mappings with no selected
|
||||
descendants are absent. Explicit false, zero, empty string, empty list, empty
|
||||
mapping, and other non-null values are serialized rather than silently
|
||||
omitted, leaving their native semantics to Narratio.
|
||||
|
||||
Native open-ended collections pass through without structural rewriting.
|
||||
Callers and composing roles may define fragments in separate inventory files
|
||||
and combine them with ordinary Ansible/Jinja expressions before assigning the
|
||||
final collection variable. The role does not merge fragments or define
|
||||
precedence among them.
|
||||
|
||||
The `narratio` account owns the mutable workspace, spool, and cache roots.
|
||||
Their setgid group-write permissions support later direct invocation by human
|
||||
operators whom the suite role adds to the `narratio` group. The root-managed
|
||||
campaign registry remains readable but not writable by those operators.
|
||||
|
||||
An immediate repeated application reports no changes. A changed checkout or a
|
||||
missing binary causes the build command to run. Account, directory, and
|
||||
configuration changes converge through their responsible Ansible modules and
|
||||
do not become build triggers.
|
||||
|
||||
## Repository Ownership
|
||||
|
||||
- `ansible-role-narratio` owns the role implementation, application account,
|
||||
runtime and campaign-root state, public variables, native root pipeline
|
||||
serialization, metadata, dependency declaration, documentation, and
|
||||
repository-local tests.
|
||||
- `../narratio` is the read-only authority for release, build, CLI,
|
||||
configuration, filesystem, and integration contracts.
|
||||
- `rakestraw-ansible` is a read-only style and historical deployment reference.
|
||||
- `ansible-role-dnd-pipeline` will later own compatible application versions,
|
||||
D&D-specific Narratio values, campaign and prompt content, secret delivery,
|
||||
and human operator membership through the standalone roles' public
|
||||
interfaces.
|
||||
- `ansible-workspace-dnd` owns this roadmap, the eventual staged implementation
|
||||
plan, and aggregate status.
|
||||
- All other repositories remain unchanged.
|
||||
|
||||
## Constraints and Settled Decisions
|
||||
|
||||
- The selected default release is lightweight tag `v2.0.0`, resolving to
|
||||
commit `ed4623bc415901134c765fe9cf06d59aa7891500`.
|
||||
- The release declares Go 1.26.0. The suite-standard `1.26/stable` Go Snap
|
||||
channel satisfies that requirement.
|
||||
- The native build uses package `./cmd/narratio`, `CGO_ENABLED=0`,
|
||||
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags
|
||||
`-s -w -X gitea.maximumdirect.net/eric/narratio/internal/buildinfo.Version=<version>`.
|
||||
- `narratio version` reports the embedded selected tag and provides the native
|
||||
observable for an explicitly requested version in integration tests.
|
||||
- Narratio discovers `/usr/local/etc/narratio/pipeline.yml` before
|
||||
`/etc/narratio/pipeline.yml`; the role manages the first path by default.
|
||||
- `whisperx.transcribe_url` is the only pipeline field without an application
|
||||
default that is required for pipeline validation. The role therefore exposes
|
||||
`narratio_whisperx_transcribe_url` as a required public input rather than
|
||||
inventing a deployment endpoint.
|
||||
- Workspace, campaign, spool, and cache roots are concrete role defaults
|
||||
because the role creates and owns the corresponding filesystem state. These
|
||||
are intentional deployment policy, not a duplicate database of application
|
||||
defaults.
|
||||
- All other optional configuration variables use YAML null defaults and
|
||||
template conditions use `is not none`. Parent mappings are emitted only
|
||||
when at least one descendant is non-null.
|
||||
- Strings and collections are serialized with Ansible or Jinja filters rather
|
||||
than hand-written YAML quoting.
|
||||
- `narratio_publish_outputs`, `narratio_notarius_references`,
|
||||
`narratio_notarius_outputs`, `narratio_scriptorium_artifacts`, and
|
||||
`narratio_scriptorium_artifact_families` represent their complete native
|
||||
fields. Caller-side composition is permitted, but the role supplies no merge
|
||||
behavior.
|
||||
- Credential configuration contains environment-variable names only. Secret
|
||||
values remain outside the role and managed pipeline document.
|
||||
- The configuration directory is `root:narratio` mode `0750`; the pipeline
|
||||
file is `root:narratio` mode `0640`.
|
||||
- Mutable runtime roots are `narratio:narratio` mode `2775`. The campaign root
|
||||
is `root:narratio` mode `0755` because version-controlled content is
|
||||
populated by a separate owner and is not operator-edited on the host.
|
||||
- Tasks installing dependencies or managing privileged 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.
|
||||
|
||||
## Fixed Public Interface
|
||||
|
||||
### Installation and Managed Filesystem
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `narratio_version` | `v2.0.0` | Selected Git revision and embedded build version |
|
||||
| `narratio_repository_url` | `https://gitea.maximumdirect.net/eric/narratio.git` | Source repository |
|
||||
| `narratio_source_dir` | `/usr/local/src/narratio` | Managed source checkout |
|
||||
| `narratio_binary_path` | `/usr/local/bin/narratio` | Installed executable |
|
||||
| `narratio_manage_build_dependencies` | `true` | Whether to install Git and Go |
|
||||
| `narratio_go_snap_channel` | `1.26/stable` | Go Snap channel |
|
||||
| `narratio_go_binary` | `/snap/bin/go` | Go executable used for the build |
|
||||
| `narratio_user` | `narratio` | System account owning mutable runtime state |
|
||||
| `narratio_group` | `narratio` | System group sharing mutable runtime state |
|
||||
| `narratio_config_path` | `/usr/local/etc/narratio/pipeline.yml` | Managed root pipeline document |
|
||||
| `narratio_workspace_root` | `/var/lib/narratio` | Managed workspace root and account home |
|
||||
| `narratio_campaigns_root` | `/usr/local/share/narratio/campaigns` | Managed campaign registry root |
|
||||
| `narratio_spool_root` | `/var/spool/narratio` | Managed spool root |
|
||||
| `narratio_cache_root` | `/var/cache/narratio` | Managed cache root |
|
||||
|
||||
Changing a managed root changes both its rendered pipeline value and the
|
||||
directory the role manages. The role does not infer additional arbitrary paths
|
||||
embedded inside caller-supplied open-ended collections.
|
||||
|
||||
### Pipeline Structure and Storage
|
||||
|
||||
Except where a default is shown, every variable below defaults to null and is
|
||||
omitted when null.
|
||||
|
||||
| Variable | Default | Native field |
|
||||
| --- | --- | --- |
|
||||
| `narratio_configkit_imports` | `null` | `configkit.imports` |
|
||||
| `narratio_workspace_cleanup_after_publish` | `null` | `workspace.cleanup_after_publish` |
|
||||
| `narratio_campaigns_default_campaign_id` | `null` | `campaigns.default_campaign_id` |
|
||||
| `narratio_storage_backend` | `null` | `storage.backend` |
|
||||
| `narratio_storage_s3_bucket` | `null` | `storage.s3.bucket` |
|
||||
| `narratio_storage_s3_root_prefix` | `null` | `storage.s3.root_prefix` |
|
||||
| `narratio_storage_s3_region` | `null` | `storage.s3.region` |
|
||||
| `narratio_storage_s3_endpoint` | `null` | `storage.s3.endpoint` |
|
||||
| `narratio_storage_s3_force_path_style` | `null` | `storage.s3.force_path_style` |
|
||||
| `narratio_storage_s3_access_key_id` | `null` | `storage.s3.access_key_id` environment-variable name |
|
||||
| `narratio_storage_s3_secret_access_key` | `null` | `storage.s3.secret_access_key` environment-variable name |
|
||||
| `narratio_spool_delete_audio_after_publish` | `null` | `spool.delete_audio_after_publish` |
|
||||
| `narratio_cache_s3_audio` | `null` | `cache.s3_audio` |
|
||||
| `narratio_publish_enabled` | `null` | `publish.enabled` |
|
||||
| `narratio_publish_upload_run` | `null` | `publish.upload_run` |
|
||||
| `narratio_publish_outputs` | `null` | Complete native `publish.outputs` list |
|
||||
|
||||
### WhisperX, Seriatim, and Audita
|
||||
|
||||
| Variable | Default | Native field |
|
||||
| --- | --- | --- |
|
||||
| `narratio_whisperx_transcribe_url` | required | `whisperx.transcribe_url` |
|
||||
| `narratio_whisperx_language` | `null` | `whisperx.language` |
|
||||
| `narratio_whisperx_timeout` | `null` | `whisperx.timeout` |
|
||||
| `narratio_whisperx_retries` | `null` | `whisperx.retries` |
|
||||
| `narratio_whisperx_retry_delay` | `null` | `whisperx.retry_delay` |
|
||||
| `narratio_whisperx_concurrency` | `null` | `whisperx.concurrency` |
|
||||
| `narratio_seriatim_binary` | `null` | `seriatim.binary` |
|
||||
| `narratio_seriatim_timeout` | `null` | `seriatim.timeout` |
|
||||
| `narratio_seriatim_output_schema` | `null` | `seriatim.output_schema` |
|
||||
| `narratio_seriatim_coalesce_gap` | `null` | `seriatim.coalesce_gap` |
|
||||
| `narratio_seriatim_report` | `null` | `seriatim.report` |
|
||||
| `narratio_seriatim_env_overlap_word_run_gap` | `null` | `seriatim.env.overlap_word_run_gap` |
|
||||
| `narratio_seriatim_env_overlap_word_run_reorder_window` | `null` | `seriatim.env.overlap_word_run_reorder_window` |
|
||||
| `narratio_seriatim_env_backchannel_max_duration` | `null` | `seriatim.env.backchannel_max_duration` |
|
||||
| `narratio_seriatim_env_filler_max_duration` | `null` | `seriatim.env.filler_max_duration` |
|
||||
| `narratio_audita_binary` | `null` | `audita.binary` |
|
||||
| `narratio_audita_timeout` | `null` | `audita.timeout` |
|
||||
| `narratio_audita_llm_api_key` | `null` | `audita.llm_api_key` environment-variable name |
|
||||
| `narratio_audita_modules` | `null` | `audita.modules` |
|
||||
| `narratio_audita_base_url` | `null` | `audita.base_url` |
|
||||
| `narratio_audita_model` | `null` | `audita.model` |
|
||||
| `narratio_audita_total_llm_concurrency` | `null` | `audita.total_llm_concurrency` |
|
||||
| `narratio_audita_proposal_llm_concurrency` | `null` | `audita.proposal_llm_concurrency` |
|
||||
| `narratio_audita_validation_model` | `null` | `audita.validation_model` |
|
||||
| `narratio_audita_validation_llm_concurrency` | `null` | `audita.validation_llm_concurrency` |
|
||||
| `narratio_audita_transcript_description` | `null` | `audita.transcript_description` |
|
||||
| `narratio_audita_config_path` | `null` | `audita.config_path` |
|
||||
| `narratio_audita_output_schema` | `null` | `audita.output_schema` |
|
||||
| `narratio_audita_work_dir_retention` | `null` | `audita.work_dir_retention` |
|
||||
| `narratio_audita_report` | `null` | `audita.report` |
|
||||
|
||||
### Transcript Stages and Rendering
|
||||
|
||||
| Variable | Default | Native field |
|
||||
| --- | --- | --- |
|
||||
| `narratio_normalize_output_path` | `null` | `normalize.output_path` |
|
||||
| `narratio_normalize_output_schema` | `null` | `normalize.output_schema` |
|
||||
| `narratio_normalize_report` | `null` | `normalize.report` |
|
||||
| `narratio_trim_enabled` | `null` | `trim.enabled` |
|
||||
| `narratio_trim_output_path` | `null` | `trim.output_path` |
|
||||
| `narratio_trim_bounds_prompt_id` | `null` | `trim.bounds.prompt_id` |
|
||||
| `narratio_trim_bounds_profile_id` | `null` | `trim.bounds.profile_id` |
|
||||
| `narratio_trim_bounds_transcript_input_name` | `null` | `trim.bounds.transcript_input_name` |
|
||||
| `narratio_trim_bounds_output_path` | `null` | `trim.bounds.output_path` |
|
||||
| `narratio_trim_bounds_timeout` | `null` | `trim.bounds.timeout` |
|
||||
| `narratio_trim_bounds_render_debug` | `null` | `trim.bounds.render_debug` |
|
||||
| `narratio_trim_bounds_render_output_path` | `null` | `trim.bounds.render_output_path` |
|
||||
| `narratio_trim_seriatim_report` | `null` | `trim.seriatim.report` |
|
||||
| `narratio_render_enabled` | `null` | `render.enabled` |
|
||||
| `narratio_render_format` | `null` | `render.format` |
|
||||
| `narratio_render_title` | `null` | `render.title` |
|
||||
| `narratio_render_include_timestamps` | `null` | `render.include_timestamps` |
|
||||
| `narratio_render_include_segment_ids` | `null` | `render.include_segment_ids` |
|
||||
| `narratio_render_include_metadata` | `null` | `render.include_metadata` |
|
||||
|
||||
### Scriptorium, Notarius, and Notification
|
||||
|
||||
| Variable | Default | Native field |
|
||||
| --- | --- | --- |
|
||||
| `narratio_scriptorium_binary` | `null` | `scriptorium.binary` |
|
||||
| `narratio_scriptorium_config_path` | `null` | `scriptorium.config_path` |
|
||||
| `narratio_scriptorium_timeout` | `null` | `scriptorium.timeout` |
|
||||
| `narratio_scriptorium_render_debug` | `null` | `scriptorium.render_debug` |
|
||||
| `narratio_scriptorium_artifacts` | `null` | Complete native `scriptorium.artifacts` map |
|
||||
| `narratio_scriptorium_artifact_families` | `null` | Complete native `scriptorium.artifact_families` map |
|
||||
| `narratio_notarius_enabled` | `null` | `notarius.enabled` |
|
||||
| `narratio_notarius_binary` | `null` | `notarius.binary` |
|
||||
| `narratio_notarius_config_path` | `null` | `notarius.config_path` |
|
||||
| `narratio_notarius_pipeline_id` | `null` | `notarius.pipeline_id` |
|
||||
| `narratio_notarius_timeout` | `null` | `notarius.timeout` |
|
||||
| `narratio_notarius_working_directory` | `null` | `notarius.working_directory` |
|
||||
| `narratio_notarius_references` | `null` | Complete native `notarius.references` map |
|
||||
| `narratio_notarius_outputs` | `null` | Complete native `notarius.outputs` map |
|
||||
| `narratio_notification_mode` | `null` | `notification.mode` |
|
||||
|
||||
## Simplest Viable Implementation
|
||||
|
||||
The production task flow is:
|
||||
|
||||
1. Assert the supported platform and architecture.
|
||||
2. Install Git and Go when dependency management is enabled.
|
||||
3. Create the Narratio system group and account.
|
||||
4. Create the source and configuration parent directories.
|
||||
5. Create the mutable runtime roots and read-only campaign registry root.
|
||||
6. Check out the selected Narratio revision with `ansible.builtin.git`.
|
||||
7. Inspect only whether the installed binary exists, because that result is
|
||||
needed to decide whether the imperative build command must run.
|
||||
8. Build directly to the selected binary path when the checkout changed or
|
||||
the binary is absent.
|
||||
9. Converge binary ownership and mode with `ansible.builtin.file`.
|
||||
10. Render the root pipeline document with one
|
||||
`ansible.builtin.template` task.
|
||||
|
||||
The build command uses `narratio_go_binary` and runs only under the two stated
|
||||
conditions. Ordinary modules own all other state checks. No role-private state,
|
||||
pre-build version interrogation, post-build validation, configuration
|
||||
validation, or redundant filesystem inspection belongs in production tasks.
|
||||
|
||||
The template is necessarily larger than those of the downstream roles because
|
||||
Narratio's native pipeline schema is larger. Its logic remains mechanical:
|
||||
serialize the required URL and role-owned roots, test each optional field with
|
||||
`is not none`, emit a parent section only when needed, and pass native
|
||||
collections through unchanged.
|
||||
|
||||
## Rationale and Alternatives
|
||||
|
||||
Narratio's configuration is broad, but a field-specific interface preserves
|
||||
discoverability, argument validation, stable inventory names, and a clean
|
||||
composition boundary for the suite role. A raw complete-document variable
|
||||
would make the template shorter but would discard those benefits and conflict
|
||||
with the established configuration policy. Open-ended native collections are
|
||||
kept whole because decomposing caller-defined keys would create a second schema
|
||||
and make inventory composition harder.
|
||||
|
||||
Requiring the WhisperX URL is preferable to installing a configuration that
|
||||
Narratio cannot validate or inventing an endpoint that might silently direct
|
||||
work to the wrong service. The baseline integration invocation supplies a
|
||||
non-contacted test URL; production callers supply their actual endpoint.
|
||||
|
||||
The standalone role creates the application account and directory permissions
|
||||
because those are Narratio runtime requirements. It does not select human
|
||||
operators, because membership is deployment-wide policy and belongs in the
|
||||
suite role.
|
||||
|
||||
ConfigKit imports and profiles remain available to advanced callers, but the
|
||||
role manages only the canonical root document. This avoids a parallel raw-file
|
||||
deployment subsystem. A caller that selects imports or profiles is responsible
|
||||
for installing those additional files by another role or play.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### Required Role Behavior
|
||||
|
||||
- The role rejects unsupported platforms before modifying application state.
|
||||
- On a supported host, it installs the selected Narratio source release and
|
||||
builds the binary with the upstream release contract.
|
||||
- The system account, source, binary, configuration, runtime roots, and
|
||||
campaign root converge to the paths, ownership, and modes selected above
|
||||
through the responsible Ansible modules.
|
||||
- With only `narratio_whisperx_transcribe_url` supplied, the rendered pipeline
|
||||
contains that URL and the four role-owned roots, omits unselected optional
|
||||
policy, and is accepted by Narratio's native configuration validator.
|
||||
- Each non-null configuration variable renders its corresponding native field.
|
||||
Null fields and empty parent sections are omitted, while intentional falsey
|
||||
values are retained.
|
||||
- Caller-supplied open-ended collections are rendered without structural
|
||||
rewriting, and independently defined values can be composed before
|
||||
assignment.
|
||||
- A changed checkout or missing binary causes the imperative build to run. An
|
||||
immediate repeated application with unchanged inputs reports no changes.
|
||||
- Dependency opt-out accepts a caller-supplied `narratio_go_binary`.
|
||||
- Root-owned operations use task-level privilege escalation; play-level
|
||||
escalation is not required.
|
||||
- Defaults, argument specifications, template behavior, README, and metadata
|
||||
remain aligned with the public interface.
|
||||
- Production tasks contain no role-private state, redundant probes,
|
||||
application self-tests, or speculative guarantees.
|
||||
- No repository other than `ansible-role-narratio` and the workspace control
|
||||
repository is modified.
|
||||
|
||||
### Required Validation
|
||||
|
||||
- Syntax checking and production-profile ansible-lint pass.
|
||||
- A baseline invocation supplies only the required WhisperX URL, exercises the
|
||||
installed application by validating the managed pipeline as the Narratio
|
||||
account, and is followed immediately by a role application reporting no
|
||||
changes. It does not snapshot the role's current default tag or complete
|
||||
default document.
|
||||
- One explicitly selected-version case requests `v2.0.0` and verifies that
|
||||
`narratio version` reports `v2.0.0`. The assertion proves caller-controlled
|
||||
version selection, not that `v2.0.0` remains the role default.
|
||||
- One recovery case removes the binary, disables dependency management,
|
||||
supplies a caller-selected Go executable, confirms that executable is used,
|
||||
and finishes with a clean repeated application.
|
||||
- One representative configuration case verifies selected scalar and nested
|
||||
values, selected omissions, intentional falsey values, and composed
|
||||
open-ended collections. Narratio's native `config validate` accepts the
|
||||
managed pipeline, and an immediate repeated application reports no changes.
|
||||
- Tests do not assert task names or order, individual task results, exact
|
||||
current defaults, complete configuration snapshots, public-variable counts,
|
||||
trusted-module account, directory, file, package, checkout, or template
|
||||
postconditions, or an exhaustive negative platform matrix.
|
||||
|
||||
## Dependencies and Follow-up Work
|
||||
|
||||
The managed host requires access to the Narratio Git repository, Ubuntu Snap
|
||||
infrastructure, and Go module sources. Useful pipeline execution also requires
|
||||
a reachable WhisperX service, the four downstream application binaries and
|
||||
their configuration, campaign and session inputs, prompt content, and any
|
||||
selected object-storage or model credentials. Those remain caller
|
||||
responsibilities for this standalone feature.
|
||||
|
||||
With this feature complete, all five standalone application roles have stable
|
||||
public interfaces. The next unit can design the suite-level pipeline role,
|
||||
including dependency composition, compatible version selection, D&D pipeline
|
||||
policy, campaign and prompt deployment, secrets, and operator group membership.
|
||||
|
||||
The role was implemented in `ansible-role-narratio` commits `3be78d8` and
|
||||
`0e8ad9f`, then finalized after independent review by remediation commit
|
||||
`7feff47`. Its complete integration suite passes.
|
||||
|
||||
## Potential Future Hardening
|
||||
|
||||
- Build into a temporary path before replacing the installed executable.
|
||||
- Verify source signatures or release artifacts.
|
||||
- Detect compiler, build-command, or out-of-band binary changes.
|
||||
- Validate configuration during production convergence.
|
||||
- Manage imported fragments or profile overlays if a concrete standalone-role
|
||||
use case requires them.
|
||||
- Add a scheduler, service, or non-interactive execution environment if later
|
||||
operating requirements select one.
|
||||
- Support Narratio's published binary artifacts as part of a future suite-wide
|
||||
installation-model change.
|
||||
- Add broader platform coverage only when supported-platform behavior expands.
|
||||
@@ -0,0 +1,382 @@
|
||||
# Feature 0006: Pipeline Role Composition Foundation
|
||||
|
||||
Status: ready
|
||||
|
||||
## Summary
|
||||
|
||||
Establish `ansible-role-dnd-pipeline` as the independently developed
|
||||
suite-level role that composes the five completed application roles. The
|
||||
feature provides a reproducible dependency manifest, a small suite-owned
|
||||
public interface, compatible application-version selection, and the native
|
||||
cross-application paths Narratio needs to find the installed tools.
|
||||
|
||||
This is the foundation of the complete D&D deployment, not the complete
|
||||
deployment itself. Campaign data, the prompt library, operator access, secret
|
||||
delivery, and opinionated D&D processing policy remain later pipeline-role
|
||||
features.
|
||||
|
||||
## Problem or Opportunity
|
||||
|
||||
The five standalone application roles are implemented, tested, and
|
||||
independently usable. The `ansible-role-dnd-pipeline` repository still contains
|
||||
only its initial README and license, so consumers must currently discover,
|
||||
install, version, and invoke every role separately and manually connect their
|
||||
paths.
|
||||
|
||||
The suite needs one composition boundary before it can add D&D-specific
|
||||
content and policy. Establishing that boundary first keeps later work focused:
|
||||
subsequent features can add suite behavior without reopening how dependencies
|
||||
are named, installed, invoked, or configured.
|
||||
|
||||
## Governing Policies
|
||||
|
||||
- [The Ansible house style](../../ansible.md) governs role composition, public
|
||||
variables, task structure, and the use of downstream role interfaces.
|
||||
- [The testing house style](../../testing.md) governs repository-local
|
||||
validation. Tests exercise the assembled role through native outcomes and
|
||||
clean repeated convergence without reproducing the standalone suites.
|
||||
- [The MVP roadmap](../mvp.md) fixes the supported platform, independently
|
||||
released application roles, Git-hosted role dependencies, source-build
|
||||
model, and suite/collection boundary.
|
||||
- [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md)
|
||||
requires the smallest direct composition and rejects supplemental state or
|
||||
verification machinery without a selected requirement.
|
||||
|
||||
## Scope
|
||||
|
||||
- Turn `ansible-role-dnd-pipeline` into a conventional standalone Ansible role
|
||||
with defaults, argument specifications, metadata, dependency manifests,
|
||||
documentation, and focused integration coverage.
|
||||
- Install the five standalone roles from their Git repositories under the
|
||||
canonical names `rakestraw.audita`, `rakestraw.narratio`,
|
||||
`rakestraw.notarius`, `rakestraw.seriatim`, and `rakestraw.scriptorium`.
|
||||
- Pin the development dependency manifest to the reviewed commits that
|
||||
completed the five standalone roles. Preserve the existing release policy
|
||||
that replaces development commits with immutable role tags before a
|
||||
released suite or collection is published.
|
||||
- Invoke all five application roles as declared role dependencies in a fixed,
|
||||
readable order.
|
||||
- Select one known-compatible default application release for each component:
|
||||
Audita `v0.9.1`, Narratio `v2.0.0`, Notarius `v0.6.0`, Seriatim `v1.5.0`,
|
||||
and Scriptorium `v0.13.0`.
|
||||
- Expose one suite-level dependency-management choice, Go Snap channel, and Go
|
||||
executable, then pass those values to every application role.
|
||||
- Require a suite-level WhisperX transcription URL and pass it to the Narratio
|
||||
role.
|
||||
- Configure Narratio with the standard binary and configuration paths managed
|
||||
by the composed roles so the orchestrator can find Seriatim, Audita,
|
||||
Notarius, and Scriptorium.
|
||||
- Keep dependency metadata, defaults, argument specifications, README, and
|
||||
focused repository-local tests aligned with the public contract.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Checking out or deploying the `campaigns` repository, including its
|
||||
revision and update policy.
|
||||
- Installing the `narratio-prompts` prompt library or selecting its filesystem
|
||||
layout.
|
||||
- Defining PromptKit profiles, Scriptorium backends, Notarius pipelines,
|
||||
Narratio artifacts, publish outputs, or detailed Audita policy.
|
||||
- Enabling Notarius in the Narratio pipeline before a usable Notarius pipeline
|
||||
definition is supplied.
|
||||
- Selecting human operators or changing their group membership.
|
||||
- Defining, storing, templating, or injecting secret values or environment
|
||||
files.
|
||||
- Running a real recording through the end-to-end D&D workflow.
|
||||
- Bundling the role into `rakestraw.dnd`; collection incorporation remains the
|
||||
next repository boundary after the standalone pipeline role is functional.
|
||||
- Publishing or tagging any role or collection release.
|
||||
- Duplicating every public variable from every application role behind a
|
||||
`dnd_pipeline_` alias.
|
||||
- Reimplementing application installation, configuration templates, account
|
||||
creation, or platform validation in the pipeline role.
|
||||
- Supporting partial component installation, per-component enable switches,
|
||||
removal, or migration from the legacy proof-of-concept role.
|
||||
- Probing downstream state, inspecting task results, or validating a
|
||||
successful downstream operation during production convergence.
|
||||
- Testing every application-role behavior again at the suite level.
|
||||
|
||||
## Target End State
|
||||
|
||||
A consumer first installs the pipeline role's declared Git role dependencies,
|
||||
then applies `rakestraw.dnd_pipeline` with a WhisperX transcription URL. The
|
||||
role invokes the five standalone roles, which install their selected sources,
|
||||
binaries, native configuration, and Narratio runtime state using their own
|
||||
public contracts.
|
||||
|
||||
The pipeline role selects the five compatible application versions as one
|
||||
set. A caller may replace an individual selection through the corresponding
|
||||
suite variable without editing the dependency declaration or addressing the
|
||||
application role directly. Shared dependency management, Go channel, and Go
|
||||
executable choices likewise flow consistently to all five roles.
|
||||
|
||||
Narratio's managed pipeline document names the installed Seriatim, Audita,
|
||||
Notarius, and Scriptorium executable paths and the managed configuration paths
|
||||
for the configured applications. Notarius remains installed but is not enabled
|
||||
as a Narratio stage by this foundation feature. All other optional application
|
||||
settings retain their standalone-role defaults unless a caller supplies the
|
||||
underlying application role variable directly.
|
||||
|
||||
The pipeline role does not own or reproduce downstream templates. It composes
|
||||
the roles through their public variables and lets each role converge its own
|
||||
state. An immediate second pipeline-role application reports no changes.
|
||||
|
||||
This intentionally minimal interface is a foundation, not the pipeline role's
|
||||
final policy surface. Later features will give the pipeline role concrete,
|
||||
opinionated D&D defaults for Audita, Narratio, Notarius, Seriatim, and
|
||||
Scriptorium through the standalone roles' existing field-specific variables.
|
||||
Those values will remain overrideable through ordinary inventory precedence.
|
||||
The suite will add only policy it deliberately owns, rather than copying every
|
||||
upstream application default.
|
||||
|
||||
## Repository Ownership
|
||||
|
||||
- `ansible-role-dnd-pipeline` owns the dependency manifest, suite public
|
||||
interface, dependency declarations, cross-application path wiring,
|
||||
repository documentation, and focused integration suite. This is the only
|
||||
implementation repository changed by the feature.
|
||||
- `ansible-role-{audita,narratio,notarius,seriatim,scriptorium}` are read-only
|
||||
dependency sources and the authorities for their respective public role
|
||||
interfaces. Their reviewed commits define the development dependency set.
|
||||
- `../{audita,narratio,notarius,seriatim,scriptorium}` remain read-only
|
||||
authorities for application behavior.
|
||||
- `rakestraw-ansible` is a read-only style and historical deployment-policy
|
||||
reference. Its monolithic installation and templating are not copied.
|
||||
- `assets/campaigns` and `assets/narratio-prompts` are read-only authorities
|
||||
for the content and layouts that later pipeline-role features will deploy.
|
||||
Their availability in the workspace does not bring content deployment into
|
||||
this composition-foundation feature.
|
||||
- `ansible-collection-dnd` remains unchanged until collection assembly is
|
||||
selected as a later feature.
|
||||
- `ansible-workspace-dnd` owns this roadmap, the eventual staged plan, the
|
||||
settled MVP decisions, and aggregate status.
|
||||
|
||||
## Constraints and Settled Decisions
|
||||
|
||||
- The standalone role is named `dnd_pipeline` in the `rakestraw` Galaxy
|
||||
namespace. It will later be incorporated into the collection under the
|
||||
shorter consumer-facing name `rakestraw.dnd.pipeline`.
|
||||
- Git dependencies are installed with these canonical role names:
|
||||
|
||||
| Role | Repository | Development revision |
|
||||
| --- | --- | --- |
|
||||
| `rakestraw.audita` | `https://gitea.maximumdirect.net/eric/ansible-role-audita.git` | `d2d0b9d00b3b491ce7613ccfc8f686f3d1fa0896` |
|
||||
| `rakestraw.narratio` | `https://gitea.maximumdirect.net/eric/ansible-role-narratio.git` | `7feff4728a5968b6b1dd87e83add9fa1a9066b18` |
|
||||
| `rakestraw.notarius` | `https://gitea.maximumdirect.net/eric/ansible-role-notarius.git` | `cfecf37261f2595d45113235c591ee102d6f181f` |
|
||||
| `rakestraw.seriatim` | `https://gitea.maximumdirect.net/eric/ansible-role-seriatim.git` | `e08c63c0b078658bdfa2d10a2e6e1e4f9372a075` |
|
||||
| `rakestraw.scriptorium` | `https://gitea.maximumdirect.net/eric/ansible-role-scriptorium.git` | `8f47aa802a5e0c9dae9c0f43a1c70b3512b2c8b2` |
|
||||
|
||||
- Commit pins are appropriate for active development because the role
|
||||
repositories do not yet publish release tags. A release must use immutable
|
||||
role tags under the policy already fixed in the MVP roadmap.
|
||||
- `requirements.yml` is the consumer and test bootstrap manifest for the five
|
||||
Git roles. `collections/requirements.yml` declares the pinned
|
||||
`community.general` dependency needed transitively by those roles.
|
||||
- `meta/main.yml` declares the five application roles as dependencies and maps
|
||||
the suite-owned inputs to their existing public variables. It does not use
|
||||
an implementation-specific loader role.
|
||||
- Dependencies execute in this order: Seriatim, Audita, Notarius,
|
||||
Scriptorium, then Narratio. The order makes the downstream tools conceptually
|
||||
available before the orchestrator, but the role does not add probes or
|
||||
runtime validation to enforce the order's postconditions.
|
||||
- Repeated Git, APT, and Snap declarations inside the five roles are accepted.
|
||||
Their modules are idempotent, and consolidating them would weaken standalone
|
||||
role ownership for no selected benefit.
|
||||
- The suite owns only choices that must be coordinated across applications or
|
||||
recorded as a compatible set. It does not alias the complete downstream
|
||||
interfaces. Unmapped application-specific variables retain their ordinary
|
||||
Ansible behavior and may be supplied directly by advanced callers.
|
||||
- The preceding boundary governs this composition foundation only; it does not
|
||||
make the finished pipeline role policy-neutral. Later D&D-configuration
|
||||
features will supply opinionated values directly through the downstream
|
||||
roles' public variables, preserving inventory overrides without introducing
|
||||
parallel templates or complete shadow interfaces.
|
||||
- The feature uses the standard application paths fixed by the MVP and current
|
||||
standalone roles:
|
||||
|
||||
| Purpose | Path |
|
||||
| --- | --- |
|
||||
| Seriatim executable | `/usr/local/bin/seriatim` |
|
||||
| Audita executable | `/usr/local/bin/audita` |
|
||||
| Audita configuration | `/usr/local/etc/audita/config.yml` |
|
||||
| Notarius executable | `/usr/local/bin/notarius` |
|
||||
| Notarius configuration | `/usr/local/etc/notarius/config.yml` |
|
||||
| Scriptorium executable | `/usr/local/bin/scriptorium` |
|
||||
| Scriptorium configuration | `/usr/local/etc/scriptorium/config.yml` |
|
||||
|
||||
- Relocating those coordinated paths is not a requirement for this feature.
|
||||
If a real deployment needs relocation, a later feature may introduce a
|
||||
small set of coherent suite path variables rather than exposing mismatched
|
||||
per-role overrides.
|
||||
- Notarius is installed because it is part of the suite, but
|
||||
`narratio_notarius_enabled` remains null until a later feature supplies a
|
||||
complete D&D Notarius pipeline and explicitly enables it.
|
||||
- Tasks requiring elevated access remain owned by the downstream roles and
|
||||
use their task-level `become: true`; the pipeline role does not require
|
||||
play-level escalation.
|
||||
|
||||
## Fixed Public Interface
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `dnd_pipeline_audita_version` | `v0.9.1` | Audita application revision selected for the compatible set |
|
||||
| `dnd_pipeline_narratio_version` | `v2.0.0` | Narratio application revision selected for the compatible set |
|
||||
| `dnd_pipeline_notarius_version` | `v0.6.0` | Notarius application revision selected for the compatible set |
|
||||
| `dnd_pipeline_seriatim_version` | `v1.5.0` | Seriatim application revision selected for the compatible set |
|
||||
| `dnd_pipeline_scriptorium_version` | `v0.13.0` | Scriptorium application revision selected for the compatible set |
|
||||
| `dnd_pipeline_manage_build_dependencies` | `true` | Whether every application role manages Git and Go |
|
||||
| `dnd_pipeline_go_snap_channel` | `1.26/stable` | Go Snap channel passed to every application role |
|
||||
| `dnd_pipeline_go_binary` | `/snap/bin/go` | Go executable passed to every application role |
|
||||
| `dnd_pipeline_whisperx_transcribe_url` | required | External WhisperX HTTP endpoint passed to Narratio |
|
||||
|
||||
Argument specifications type and document each value. The WhisperX URL is
|
||||
required because neither Narratio nor the suite has a valid universal
|
||||
endpoint. The suite version variables select application source revisions;
|
||||
they are separate from the Git revisions pinning the Ansible role
|
||||
dependencies.
|
||||
|
||||
The role intentionally has no raw map of arbitrary downstream variables and
|
||||
no parallel configuration template. Application-specific choices that are not
|
||||
part of this interface continue to use the standalone roles' documented
|
||||
variables.
|
||||
|
||||
## Simplest Viable Implementation
|
||||
|
||||
The implementation is primarily metadata:
|
||||
|
||||
1. Define the nine suite variables above in defaults and argument
|
||||
specifications, omitting a default for the required WhisperX URL.
|
||||
2. Declare the five named role dependencies in `meta/main.yml`, in the settled
|
||||
order, and pass each dependency its selected version plus the common
|
||||
dependency-management and Go values.
|
||||
3. Pass the WhisperX URL and standard downstream binary/configuration paths to
|
||||
the Narratio dependency.
|
||||
4. Add the Git-role and collection dependency manifests used by consumers and
|
||||
tests.
|
||||
5. Document installation, variables, dependency bootstrap, the boundary with
|
||||
application-specific variables, and an ordinary playbook example.
|
||||
6. Add a focused integration driver that installs dependencies in an isolated
|
||||
roles path, applies the real pipeline role, observes the assembled native
|
||||
application outcome, and requires immediate clean repeated convergence.
|
||||
|
||||
No custom tasks are required merely to prove that role dependencies ran. The
|
||||
pipeline role should not inspect downstream binaries, files, packages,
|
||||
checkouts, or registered task results during production convergence. It should
|
||||
not copy downstream defaults into facts or introduce an abstraction around
|
||||
ordinary role dependency metadata.
|
||||
|
||||
## Rationale and Alternatives
|
||||
|
||||
Using declared role dependencies reflects the actual ownership boundary: each
|
||||
application role remains responsible for its own installation and native
|
||||
configuration, while the pipeline role selects and connects them. Rewriting
|
||||
or including copies of downstream tasks would couple the suite to their
|
||||
implementations and discard the independent-release model already selected.
|
||||
|
||||
A small suite-prefixed interface makes coordinated decisions explicit without
|
||||
creating five complete shadow interfaces. Version selection belongs here
|
||||
because the suite promises a compatible application set. Build dependency and
|
||||
Go choices are common because all five roles use the same source-build model.
|
||||
The WhisperX endpoint belongs here because it is required to construct the
|
||||
Narratio configuration and is deployment-specific.
|
||||
|
||||
The standard downstream paths are suite policy rather than configurable inputs
|
||||
for this first composition feature. Exposing every source, binary, and
|
||||
configuration path would add aliases and cross-variable consistency rules
|
||||
without a demonstrated consumer need. Advanced callers can still use
|
||||
unmapped application variables where they do not conflict with coordinated
|
||||
suite policy.
|
||||
|
||||
Keeping content, operators, secrets, and D&D processing definitions out of
|
||||
this feature avoids combining several unsettled interfaces with dependency
|
||||
composition. Those features can build on a running, natively valid application
|
||||
suite and receive focused roadmaps of their own.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### Required Role Behavior
|
||||
|
||||
- A documented bootstrap command installs all five standalone roles from
|
||||
`requirements.yml` under their canonical names and installs the pinned
|
||||
collection dependency.
|
||||
- Applying the pipeline role with a valid
|
||||
`dnd_pipeline_whisperx_transcribe_url` invokes all five standalone roles and
|
||||
reaches their ordinary managed end state on Ubuntu 26.04 `amd64` or `arm64`.
|
||||
- The default suite selections install Audita `v0.9.1`, Narratio `v2.0.0`,
|
||||
Notarius `v0.6.0`, Seriatim `v1.5.0`, and Scriptorium `v0.13.0` as one
|
||||
compatible development set.
|
||||
- A caller can change each application revision through its corresponding
|
||||
`dnd_pipeline_*_version` variable.
|
||||
- The common dependency-management switch, Go channel, and Go executable are
|
||||
passed to all five roles without duplicating their installation tasks.
|
||||
- Narratio receives the required WhisperX URL and the standard executable and
|
||||
configuration paths for all four downstream applications.
|
||||
- Notarius is installed but is not enabled in the Narratio pipeline by this
|
||||
feature.
|
||||
- An immediate repeated role application with unchanged inputs reports no
|
||||
changes.
|
||||
- The role contains no copied application tasks or templates, downstream state
|
||||
probes, role-private state, custom dependency loader, or production
|
||||
self-validation.
|
||||
- Defaults, argument specifications, dependency metadata, manifests, and
|
||||
README remain aligned with the fixed interface.
|
||||
- No implementation repository other than `ansible-role-dnd-pipeline` is
|
||||
modified.
|
||||
|
||||
### Required Validation
|
||||
|
||||
- YAML syntax checking and production-profile ansible-lint pass for the role
|
||||
and its test playbooks.
|
||||
- The integration driver installs the five Git dependencies into a fresh,
|
||||
isolated role path from the same manifest documented for consumers.
|
||||
- One baseline application runs the real pipeline role with a test WhisperX
|
||||
URL, exercises each installed application through a practical native smoke
|
||||
or configuration command, validates Narratio's assembled configuration
|
||||
natively, and is followed immediately by a role application reporting no
|
||||
changes.
|
||||
- One representative application explicitly selects Seriatim `v1.4.0`
|
||||
through `dnd_pipeline_seriatim_version` and observes that selection through
|
||||
Seriatim's native version interface. This proves suite forwarding without
|
||||
asserting that any release remains the default or promising that arbitrary
|
||||
component combinations are compatible.
|
||||
- Tests do not repeat the standalone roles' missing-binary, custom-Go,
|
||||
template-branch, file-metadata, package, Git, or platform matrices.
|
||||
- Tests do not assert dependency task order, exact current default values,
|
||||
role-variable counts, individual task results, or trusted-module
|
||||
postconditions.
|
||||
|
||||
## Dependencies and Follow-up Work
|
||||
|
||||
The five application-role implementations and public interfaces are complete.
|
||||
The managed host must be able to reach their application source repositories,
|
||||
Ubuntu Snap infrastructure, Go module sources, and the caller-supplied
|
||||
WhisperX service.
|
||||
|
||||
After this foundation is implemented and reviewed, later pipeline-role
|
||||
features must settle and implement:
|
||||
|
||||
- prompt-library checkout and Scriptorium integration;
|
||||
- campaign checkout, revision policy, and deployment;
|
||||
- D&D-specific Audita, Notarius, Scriptorium, and Narratio policy;
|
||||
- operator-selection and group-membership behavior;
|
||||
- pipeline-wide secret delivery; and
|
||||
- an end-to-end pipeline validation scenario.
|
||||
|
||||
Collection assembly remains a separate feature after the standalone pipeline
|
||||
role has a stable contract. Before any released dependency manifest or
|
||||
collection is published, the standalone roles must receive immutable release
|
||||
tags and the development commit pins must be replaced by those tags.
|
||||
|
||||
The D&D-policy follow-up must inspect the asset repositories and current
|
||||
application contracts, select concrete suite defaults for all five
|
||||
applications, and document how callers override them. It should reuse the
|
||||
standalone roles' field-specific variables rather than adding pipeline-owned
|
||||
configuration templates or duplicating every downstream setting behind a new
|
||||
alias.
|
||||
|
||||
## Potential Future Hardening
|
||||
|
||||
- Verify signed role or application releases.
|
||||
- Apply an allowlist to dependency or application repository origins.
|
||||
- Add policy for hosts whose installed dependency roles differ from the
|
||||
manifest used by the controller.
|
||||
@@ -20,6 +20,8 @@ for scope, rationale, target end state, and acceptance criteria.
|
||||
zero-based, decimal, nested, or nonsequential stage identifiers.
|
||||
- Before each stage, confirm its preconditions and the working-tree state of
|
||||
its owning repository.
|
||||
- Before each stage, read every document listed in that stage's Required Policy
|
||||
Review. Do not rely on policy recalled from an earlier stage.
|
||||
- Preserve unrelated and pre-existing changes.
|
||||
- Do not make unresolved product or architecture decisions during execution;
|
||||
stop and report the decision required.
|
||||
@@ -52,6 +54,21 @@ for scope, rationale, target end state, and acceptance criteria.
|
||||
|
||||
State the single outcome delivered by this stage.
|
||||
|
||||
### Required Policy Review
|
||||
|
||||
Before beginning this stage, read:
|
||||
|
||||
- `AGENTS.md`
|
||||
- `docs/orientation.md`
|
||||
- `docs/conventions.md`
|
||||
- `<docs/ansible.md, docs/testing.md, and/or docs/planning.md as applicable>`
|
||||
|
||||
Replace the placeholder with every specialized policy applicable to this
|
||||
stage. Include `docs/ansible.md` for Ansible design or implementation,
|
||||
`docs/testing.md` for test work, and `docs/planning.md` for workspace planning
|
||||
or progress management. Do not list an inapplicable policy merely for
|
||||
completeness.
|
||||
|
||||
### Preconditions
|
||||
|
||||
- List facts that must be true before editing begins.
|
||||
|
||||
@@ -1,12 +1,379 @@
|
||||
# Implementation Plan
|
||||
# Implementation Plan 0006: Establish Pipeline Role Composition
|
||||
|
||||
Status: pending
|
||||
Status: ready
|
||||
|
||||
No implementation plan is currently active. Feature 0002 was completed in
|
||||
`ansible-role-audita` through commit `3a8c21f`; its durable scope and rationale
|
||||
remain in
|
||||
[the Feature 0002 roadmap](features/0002-audita-source-installation-and-configuration.md),
|
||||
and its review history remains in [the remediation record](remediation.md).
|
||||
Target executor: GPT-5.6-Terra
|
||||
|
||||
Select and approve the next feature roadmap before replacing this notice with
|
||||
a new staged implementation plan.
|
||||
Feature roadmap:
|
||||
[Feature 0006: Pipeline Role Composition Foundation](features/0006-pipeline-role-composition-foundation.md)
|
||||
|
||||
Active plan location: `docs/roadmap/implementation.md`
|
||||
|
||||
## Objective
|
||||
|
||||
Implement the independently developed `rakestraw.dnd_pipeline` role defined by
|
||||
Feature 0006. Compose the five completed standalone application roles through
|
||||
ordinary dependency metadata, install them reproducibly from a Git dependency
|
||||
manifest, expose the approved suite-level variables, and wire Narratio to the
|
||||
standard downstream application paths.
|
||||
|
||||
The feature roadmap remains authoritative for scope, rationale, target end
|
||||
state, public variables, dependency revisions, and acceptance criteria.
|
||||
|
||||
## Execution Rules
|
||||
|
||||
- Execute Stage 1 and Stage 2 in numeric order.
|
||||
- Immediately before each stage, read every document in that stage's Required
|
||||
Policy Review, then confirm its preconditions and the owning repository's
|
||||
working-tree state.
|
||||
- Modify only `ansible-role-dnd-pipeline`. Treat the workspace control
|
||||
repository, standalone application roles, application sources, asset
|
||||
repositories, collection, and proof of concept as read-only during
|
||||
out-of-band implementation.
|
||||
- Preserve unrelated changes. Stop if the pipeline-role repository is
|
||||
unexpectedly dirty at a stage boundary.
|
||||
- Use ordinary role dependency metadata. Do not copy downstream tasks or
|
||||
templates, add a loader role, or surround role invocation with state probes
|
||||
or result inspection.
|
||||
- Define only the nine suite-owned variables fixed by the feature roadmap. Do
|
||||
not alias the complete standalone interfaces or add raw downstream-variable
|
||||
maps, path overrides, component switches, content settings, operator
|
||||
settings, or secret settings.
|
||||
- Pass the common build-dependency switch, Go channel, and Go executable to
|
||||
all five dependencies. Pass each selected application version only to its
|
||||
corresponding dependency.
|
||||
- Pass the required WhisperX URL and the roadmap's fixed downstream binary and
|
||||
configuration paths to Narratio. Install Notarius without enabling it in
|
||||
Narratio.
|
||||
- Trust each dependency to establish its documented state. Do not test or
|
||||
reimplement APT, Snap, Git, file, template, account, or build behavior in
|
||||
production pipeline-role logic.
|
||||
- Keep behavioral tests at the composition boundary. Prove that the assembled
|
||||
applications are usable, Narratio accepts the assembled configuration, a
|
||||
suite version override reaches its application role, and an immediate
|
||||
repeat is clean. Do not rerun the standalone roles' behavior matrices.
|
||||
- Do not assert current default versions, exact dependency pins, task order,
|
||||
task traces, file metadata, package state, checkout state, or other trusted
|
||||
module postconditions in behavioral tests.
|
||||
- Use fully qualified collection names. Run each stage's validation before
|
||||
committing it, and do not begin Stage 2 if Stage 1 fails validation.
|
||||
- Commit each completed stage with its specified plain-English message. Do not
|
||||
push during out-of-band implementation.
|
||||
- Test cleanup may reapply the baseline pipeline role and remove only the
|
||||
integration driver's private temporary directory. Do not delete campaign,
|
||||
prompt, runtime, or other caller content.
|
||||
|
||||
## Starting State and Preconditions
|
||||
|
||||
- `ansible-role-dnd-pipeline` is clean on `main` at
|
||||
`1a66d177cdd5d948c94c291b718c779dbbfd1f91`, tracking `origin/main` without
|
||||
divergence.
|
||||
- This plan, the ready Feature 0006 roadmap, and the corresponding workspace
|
||||
documentation and status updates are committed before out-of-band execution
|
||||
begins.
|
||||
- The exact dependency commits fixed by Feature 0006 are reachable from their
|
||||
declared remote repositories before Stage 1 begins. At plan preparation,
|
||||
all five commits are local-only and must be pushed:
|
||||
|
||||
| Dependency | Required commit | Current `origin/main` |
|
||||
| --- | --- | --- |
|
||||
| Audita role | `d2d0b9d00b3b491ce7613ccfc8f686f3d1fa0896` | `3a8c21f0e61c62dbb603ba0f3fdfab1fd3b1de09` |
|
||||
| Narratio role | `7feff4728a5968b6b1dd87e83add9fa1a9066b18` | `b97a317f9ec9f15675e81c65af3f4a1ad8176886` |
|
||||
| Notarius role | `cfecf37261f2595d45113235c591ee102d6f181f` | `f8a3e113ef4975b2c2745cb3f08500b2206c3f21` |
|
||||
| Seriatim role | `e08c63c0b078658bdfa2d10a2e6e1e4f9372a075` | `fb8dc4100c029e25c4ab507645d75df0d739fe66` |
|
||||
| Scriptorium role | `8f47aa802a5e0c9dae9c0f43a1c70b3512b2c8b2` | `2cd69a4b2ead23b44f1aab51fd1b1f14ac326af2` |
|
||||
|
||||
- The local controller and managed-host proxy are Ubuntu 26.04 `x86_64`, with
|
||||
gathered facts and passwordless task-level privilege escalation available.
|
||||
- Workspace tooling is available in `../.venv/bin` from the pipeline-role
|
||||
repository: Ansible Core 2.21.3 and ansible-lint 26.8.0.
|
||||
- `community.general` 13.3.0 and Go Snap channel `1.26/stable` are available.
|
||||
- The five application binaries and their current managed state may already
|
||||
exist from standalone-role development. The integration suite must converge
|
||||
from that state without treating prior installation as test evidence or
|
||||
deleting unrelated content.
|
||||
- Seriatim tag `v1.4.0` remains available for the explicit suite-level version
|
||||
override case and reports `seriatim version v1.4.0` through its native
|
||||
version command.
|
||||
- Narratio can validate the baseline assembled pipeline without contacting the
|
||||
syntactically valid test WhisperX URL. Notarius remains disabled, and no
|
||||
campaign, prompt library, credentials, or session input is required for
|
||||
configuration validation.
|
||||
|
||||
## Repository Scope
|
||||
|
||||
Repository that changes:
|
||||
|
||||
- `ansible-role-dnd-pipeline`: public interface, dependency metadata and
|
||||
manifests, documentation, and focused repository-local integration suite.
|
||||
|
||||
Repositories that may be inspected but must remain unchanged:
|
||||
|
||||
- `ansible-workspace-dnd`: authoritative roadmap, plan, policies, inventory,
|
||||
and status.
|
||||
- `ansible-role-{audita,narratio,notarius,seriatim,scriptorium}`: authoritative
|
||||
dependency interfaces and reviewed implementations.
|
||||
- `../{audita,narratio,notarius,seriatim,scriptorium}`: authoritative native
|
||||
application contracts.
|
||||
- `assets/campaigns` and `assets/narratio-prompts`: future content inputs,
|
||||
outside this feature.
|
||||
- `ansible-collection-dnd`: future collection assembly target.
|
||||
- `rakestraw-ansible`: historical style and deployment reference.
|
||||
- Every other repository in `workspace.yml`.
|
||||
|
||||
## Stage 1: Compose the Five Application Roles
|
||||
|
||||
### Objective
|
||||
|
||||
Create a complete standalone pipeline role whose metadata installs the five
|
||||
applications with the approved suite interface, dependency pins, and
|
||||
cross-application path wiring, then demonstrate baseline native usability and
|
||||
clean repeated convergence.
|
||||
|
||||
### Required Policy Review
|
||||
|
||||
Before beginning this stage, read:
|
||||
|
||||
- `AGENTS.md`
|
||||
- `docs/orientation.md`
|
||||
- `docs/conventions.md`
|
||||
- `docs/ansible.md`
|
||||
- `docs/testing.md`
|
||||
|
||||
### Preconditions
|
||||
|
||||
- The starting revision and tool versions above remain valid.
|
||||
- `ansible-role-dnd-pipeline` has no uncommitted changes.
|
||||
- The workspace planning commit containing this plan exists.
|
||||
- Every required dependency commit is fetchable from its roadmap-declared Git
|
||||
URL. Confirm this through a fresh `ansible-galaxy role install`; do not
|
||||
substitute local role directories for the remote dependency test.
|
||||
- Existing managed application and runtime paths contain no test-created
|
||||
corruption that prevents ordinary role convergence. Preserve any campaign,
|
||||
prompt, session, or other caller content already present.
|
||||
|
||||
### Owning Repository
|
||||
|
||||
`ansible-role-dnd-pipeline`
|
||||
|
||||
### Required Changes
|
||||
|
||||
1. Retain the existing license and create the conventional role structure:
|
||||
`defaults/main.yml`, `meta/main.yml`, `meta/argument_specs.yml`,
|
||||
`tasks/main.yml`, `requirements.yml`, `collections/requirements.yml`,
|
||||
`ansible.cfg`, and focused files under `tests/`.
|
||||
2. Declare role name `dnd_pipeline`, namespace `rakestraw`, author Eric
|
||||
Rakestraw, license `CC0-1.0`, Ubuntu 26.04 support, Ansible Core 2.18 or
|
||||
newer, the canonical issue tracker, and appropriate pipeline tags.
|
||||
3. Define exactly the Feature 0006 Fixed Public Interface in defaults and
|
||||
matching argument specifications:
|
||||
- default the five `dnd_pipeline_*_version` variables to their roadmap
|
||||
releases;
|
||||
- default `dnd_pipeline_manage_build_dependencies` to `true`;
|
||||
- default `dnd_pipeline_go_snap_channel` to `1.26/stable`;
|
||||
- default `dnd_pipeline_go_binary` to `/snap/bin/go`; and
|
||||
- require `dnd_pipeline_whisperx_transcribe_url` as a string without
|
||||
inventing a default.
|
||||
4. Add a root `requirements.yml` containing the five Git role dependencies in
|
||||
the roadmap's canonical names and at the exact reviewed commits. Add
|
||||
`collections/requirements.yml` pinning `community.general` to `13.3.0`.
|
||||
5. Declare these dependencies in `meta/main.yml`, in this order: Seriatim,
|
||||
Audita, Notarius, Scriptorium, Narratio. Map each suite version to the
|
||||
corresponding application `*_version` variable and map the common
|
||||
dependency-management, Go channel, and Go executable values to all five
|
||||
roles.
|
||||
6. In the Narratio dependency declaration, additionally pass:
|
||||
- `dnd_pipeline_whisperx_transcribe_url` as
|
||||
`narratio_whisperx_transcribe_url`;
|
||||
- `/usr/local/bin/seriatim` as `narratio_seriatim_binary`;
|
||||
- `/usr/local/bin/audita` and `/usr/local/etc/audita/config.yml` as the
|
||||
corresponding Narratio Audita values;
|
||||
- `/usr/local/bin/notarius` and `/usr/local/etc/notarius/config.yml` as the
|
||||
corresponding Narratio Notarius path values; and
|
||||
- `/usr/local/bin/scriptorium` and
|
||||
`/usr/local/etc/scriptorium/config.yml` as the corresponding Narratio
|
||||
Scriptorium values.
|
||||
Do not set `narratio_notarius_enabled` or supply D&D processing policy.
|
||||
7. Keep `tasks/main.yml` empty except for its YAML document marker if Ansible
|
||||
requires the file. Dependency metadata is the complete production
|
||||
implementation for this feature; do not add wrapper tasks, assertions,
|
||||
probes, facts, handlers, or post-dependency validation.
|
||||
8. Replace the placeholder README with concise documentation covering the
|
||||
supported platform, dependency bootstrap commands, canonical installed
|
||||
role names, all nine suite variables, required WhisperX URL, compatible
|
||||
default application set, common dependency opt-out and Go behavior,
|
||||
standard cross-application paths, direct use of unmapped standalone role
|
||||
variables, Notarius's disabled state, later collection name, deferred
|
||||
content/operators/secrets, and actual integration-test behavior.
|
||||
9. Add a baseline local integration harness with one executable
|
||||
`tests/integration` entry point. Use strict shell options,
|
||||
repository-relative paths, a mode-`0700` private temporary directory, an
|
||||
isolated roles path, an isolated collections path, syntax checking,
|
||||
production-profile ansible-lint, and best-effort cleanup that reapplies the
|
||||
baseline role and removes only the private temporary directory.
|
||||
10. Install `community.general` from `collections/requirements.yml` and install
|
||||
all five roles from `requirements.yml` into the fresh isolated roles path.
|
||||
Resolve the pipeline role itself from the working repository without
|
||||
replacing any dependency with a workspace sibling checkout.
|
||||
11. Apply the pipeline role without play-level escalation and supply only a
|
||||
syntactically valid local test value for
|
||||
`dnd_pipeline_whisperx_transcribe_url`. Exercise the installed applications
|
||||
with concise native smoke or configuration commands without asserting
|
||||
their current default versions. Validate the assembled Narratio pipeline
|
||||
natively as the `narratio` application account without contacting
|
||||
WhisperX.
|
||||
12. Immediately apply the identical baseline invocation again and require the
|
||||
aggregate recap to report `changed=0` and `failed=0`.
|
||||
13. Do not assert downstream file existence, ownership, permissions, package
|
||||
state, Git state, dependency order, exact default versions, complete
|
||||
configuration content, or individual task results. Successful native use
|
||||
and clean repeated convergence are the stage's behavioral evidence.
|
||||
|
||||
### Validation
|
||||
|
||||
From `ansible-role-dnd-pipeline`, run:
|
||||
|
||||
```text
|
||||
tests/integration
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected result: both manifests install into fresh isolated paths; syntax and
|
||||
lint pass; the real pipeline role composes all five dependencies; their native
|
||||
smoke/configuration commands and Narratio's assembled configuration validation
|
||||
succeed; the immediate repeat reports `changed=0` and `failed=0`; cleanup
|
||||
leaves the baseline suite usable; and only intended Stage 1 files are modified.
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
- Defaults and argument specifications implement exactly the nine-variable
|
||||
suite interface, with only the WhisperX URL required.
|
||||
- Git and collection manifests use the exact approved names, URLs, revisions,
|
||||
and collection version.
|
||||
- Dependency metadata contains the five roles in the settled order and passes
|
||||
only the approved coordinated values and Narratio path wiring.
|
||||
- The production role contains no duplicated downstream implementation or
|
||||
additional task machinery.
|
||||
- README and metadata accurately describe the role, bootstrap procedure,
|
||||
public interface, composition boundary, and current non-goals.
|
||||
- Fresh dependency bootstrap, static validation, baseline native behavior, and
|
||||
immediate clean convergence pass.
|
||||
- No repository outside `ansible-role-dnd-pipeline` changes.
|
||||
|
||||
### Commit
|
||||
|
||||
Commit intent: `Compose the D&D pipeline roles`
|
||||
|
||||
## Stage 2: Add Focused Composition Coverage
|
||||
|
||||
### Objective
|
||||
|
||||
Prove through one representative override that suite-owned version selection
|
||||
reaches the appropriate application role, while retaining the lean baseline
|
||||
composition test and restoring the approved default suite afterward.
|
||||
|
||||
### Required Policy Review
|
||||
|
||||
Before beginning this stage, read:
|
||||
|
||||
- `AGENTS.md`
|
||||
- `docs/orientation.md`
|
||||
- `docs/conventions.md`
|
||||
- `docs/ansible.md`
|
||||
- `docs/testing.md`
|
||||
|
||||
### Preconditions
|
||||
|
||||
- Stage 1 is committed and `ansible-role-dnd-pipeline` is otherwise clean.
|
||||
- Stage 1's complete integration entry point passes.
|
||||
- The isolated dependency bootstrap still resolves all five exact Git commits.
|
||||
- Applying the baseline pipeline inputs can restore the compatible default
|
||||
suite after the representative version override.
|
||||
|
||||
### Owning Repository
|
||||
|
||||
`ansible-role-dnd-pipeline`
|
||||
|
||||
### Required Changes
|
||||
|
||||
1. Retain the Stage 1 baseline native smoke/configuration checks and immediate
|
||||
clean repeat. Extend the existing integration entry point rather than
|
||||
introducing another framework, scenario tree, or cross-repository helper.
|
||||
2. Add one representative convergence that explicitly sets
|
||||
`dnd_pipeline_seriatim_version: v1.4.0` while supplying the same test
|
||||
WhisperX URL.
|
||||
3. Execute Seriatim's native version interface and require
|
||||
`seriatim version v1.4.0`. This proves suite-variable forwarding; do not
|
||||
inspect role defaults, dependency metadata, the source checkout, or task
|
||||
results to establish it.
|
||||
4. Immediately repeat the same explicit-version invocation and require the
|
||||
aggregate recap to report `changed=0` and `failed=0`.
|
||||
5. Ensure the cleanup trap reapplies the baseline pipeline role without the
|
||||
version override so the managed host returns to the approved compatible
|
||||
default suite on success or failure when possible.
|
||||
6. Do not add version assertions for the other applications, a common-Go
|
||||
forwarding probe, missing-binary recovery, configuration branch cases,
|
||||
platform matrices, dependency-order checks, file or package assertions, or
|
||||
an end-to-end transcript run. Those behaviors are either already owned by
|
||||
standalone suites or explicitly deferred by Feature 0006.
|
||||
7. Update the README validation section only as needed so it accurately
|
||||
describes the baseline composition, native validation, clean repeats, and
|
||||
one explicit Seriatim version-selection case.
|
||||
|
||||
### Validation
|
||||
|
||||
From `ansible-role-dnd-pipeline`, run:
|
||||
|
||||
```text
|
||||
tests/integration
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
Expected result: fresh dependency bootstrap and all Stage 1 checks still pass;
|
||||
the suite-level Seriatim override installs `v1.4.0` as observed through native
|
||||
version output; both required repeat runs report `changed=0` and `failed=0`;
|
||||
cleanup restores the baseline compatible suite; and only intended Stage 2 test
|
||||
and documentation changes are present.
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
- One explicit non-default application revision proves the suite's version
|
||||
forwarding behavior through a native application outcome.
|
||||
- Baseline composition, assembled Narratio validation, and both clean-repeat
|
||||
cases remain successful.
|
||||
- Test cleanup restores the baseline suite without deleting caller content.
|
||||
- Tests remain focused on composition and do not reproduce standalone-role
|
||||
coverage or freeze current defaults and implementation details.
|
||||
- README test documentation remains accurate.
|
||||
- No repository outside `ansible-role-dnd-pipeline` changes.
|
||||
|
||||
### Commit
|
||||
|
||||
Commit intent: `Add focused pipeline composition coverage`
|
||||
|
||||
## Final Validation and Handoff
|
||||
|
||||
After Stage 2, from `ansible-role-dnd-pipeline`, run:
|
||||
|
||||
```text
|
||||
tests/integration
|
||||
git log --oneline -2
|
||||
git status --short --branch
|
||||
cd ..
|
||||
./scripts/status
|
||||
```
|
||||
|
||||
Report both pipeline-role commit hashes, dependency-bootstrap evidence, static
|
||||
and behavioral validation results, clean-repeat evidence, baseline restoration,
|
||||
any deviation or remaining concern, and any complexity beyond dependency
|
||||
metadata with the acceptance criterion that required it.
|
||||
|
||||
Do not edit workspace planning files, mark Feature 0006 `done`, modify asset or
|
||||
dependency repositories, or push during out-of-band implementation. Completion
|
||||
requires subsequent independent review.
|
||||
|
||||
## Progress Notes
|
||||
|
||||
- No stages completed.
|
||||
|
||||
@@ -108,6 +108,15 @@ role will manage the native configuration needed to connect to it.
|
||||
cross-application configuration, D&D campaign deployment, prompt-library
|
||||
deployment, operator access, the pipeline-wide secret-delivery policy, and
|
||||
end-to-end validation.
|
||||
- Unlike the generic standalone roles, the pipeline role deliberately supplies
|
||||
opinionated, D&D-specific defaults for all five applications. It expresses
|
||||
that policy through the standalone roles' existing field-specific variables,
|
||||
keeps those values overrideable through ordinary inventory precedence, and
|
||||
does not duplicate the application roles' templates or convergence logic.
|
||||
- Pipeline defaults represent policy deliberately selected for the D&D suite;
|
||||
they do not mirror every upstream application default. Settings for which the
|
||||
suite has selected no policy remain under the application or caller's
|
||||
control.
|
||||
- The pipeline role uses the Git-hosted standalone application roles as
|
||||
dependencies. This is an intentional choice for the controlled project
|
||||
environment despite the additional repository and dependency structure and
|
||||
@@ -116,6 +125,18 @@ role will manage the native configuration needed to connect to it.
|
||||
that installs both the collection and its standalone role dependencies; a
|
||||
plain collection installation is not assumed to resolve arbitrary Git role
|
||||
dependencies by itself.
|
||||
- The standalone application roles use the canonical installed names
|
||||
`rakestraw.audita`, `rakestraw.narratio`, `rakestraw.notarius`,
|
||||
`rakestraw.seriatim`, and `rakestraw.scriptorium`.
|
||||
- The pipeline role supplies a root `requirements.yml` bootstrap manifest for
|
||||
those Git-hosted roles and a collection requirements manifest for shared
|
||||
collection dependencies. During active development, the Git roles are
|
||||
pinned to reviewed commits; released manifests replace those commits with
|
||||
immutable role release tags.
|
||||
- The pipeline role composes the five roles through ordinary Ansible role
|
||||
dependency metadata. It exposes suite-prefixed variables for the small set
|
||||
of values the suite must coordinate, and does not duplicate every downstream
|
||||
role variable behind a parallel alias.
|
||||
|
||||
This design keeps repository ownership and change blast radius aligned with
|
||||
the independently released applications while retaining a single opinionated
|
||||
@@ -176,18 +197,48 @@ application-role releases in one source repository.
|
||||
|
||||
### Accounts, ownership, and operator access
|
||||
|
||||
- The roles create a dedicated `narratio` user and `narratio` group as needed.
|
||||
- The standalone Narratio role creates a dedicated system `narratio` user and
|
||||
`narratio` group. The account uses `/var/lib/narratio` as its default home
|
||||
and has a non-login shell.
|
||||
- The `narratio` account owns Narratio's writable runtime directories.
|
||||
- Application source trees and installed binaries are owned by `root` and are
|
||||
not writable by operators or the runtime account.
|
||||
- Ordinary human users run `narratio run` and other Narratio commands directly.
|
||||
- Those operators receive the required access by membership in the `narratio`
|
||||
group.
|
||||
- Managed configuration should be owned by `root`, readable by the `narratio`
|
||||
group where needed, and remain under Ansible control rather than being
|
||||
routinely edited by operators on the host.
|
||||
- Shared runtime directories must grant the `narratio` group the write access
|
||||
needed for direct operator invocations.
|
||||
- Narratio's configuration directory is owned by `root:narratio` with mode
|
||||
`0750`, and its pipeline file is owned by `root:narratio` with mode `0640`.
|
||||
Configuration remains under Ansible control rather than being routinely
|
||||
edited by operators on the host.
|
||||
- The Narratio workspace, spool, and cache roots are owned by
|
||||
`narratio:narratio` with mode `2775`, preserving the group on created content
|
||||
and granting the shared write access needed for direct operator invocations.
|
||||
- The campaign registry root is owned by `root:narratio` with mode `0755`.
|
||||
Its content is readable by operators but is populated by the suite role and
|
||||
is not edited directly on the managed host.
|
||||
- The standalone role does not select human operators. The suite role owns the
|
||||
operator list and adds those accounts to the `narratio` group.
|
||||
|
||||
### Narratio configuration
|
||||
|
||||
- The standalone Narratio role manages the canonical root pipeline document
|
||||
at `/usr/local/etc/narratio/pipeline.yml` through a field-specific public
|
||||
variable interface.
|
||||
- The role requires a caller-supplied WhisperX transcription URL because the
|
||||
field is required by Narratio and has no valid universal deployment value.
|
||||
- Filesystem roots managed by the role have concrete defaults and are rendered
|
||||
so application configuration agrees with managed host state. Other optional
|
||||
application fields default to null, are omitted from the rendered document,
|
||||
and inherit Narratio's built-in defaults.
|
||||
- Native open-ended collections such as publish outputs, Notarius references
|
||||
and outputs, and Scriptorium artifacts and artifact families are exposed as
|
||||
complete fields. Callers may compose their final values in inventory; the
|
||||
role does not add merge or precedence behavior.
|
||||
- The root document may name ConfigKit imports, but the standalone role does
|
||||
not manage imported fragments or profile overlays. A caller that selects
|
||||
them owns their deployment.
|
||||
- Credential fields contain environment-variable names, never secret values.
|
||||
Secret delivery remains suite-level policy.
|
||||
|
||||
### Execution model
|
||||
|
||||
@@ -237,15 +288,12 @@ remain to be designed.
|
||||
|
||||
The following areas require investigation and decisions before implementation:
|
||||
|
||||
- Exact application repository URLs, default release tags, build commands,
|
||||
version-injection flags, and validation commands
|
||||
- Standalone role Galaxy names and the dependency-manifest/bootstrap layout
|
||||
- The mechanism used to incorporate the independently developed pipeline role
|
||||
into collection releases
|
||||
- Configuration contracts and filesystem requirements of Notarius, Audita,
|
||||
Seriatim, and Scriptorium
|
||||
- The prompt-library destination and its integration with Scriptorium
|
||||
- The campaign repository's checkout revision and deployment/update policy
|
||||
- Secret injection and storage
|
||||
- Operator-group membership variables and directory permission details
|
||||
- Suite-level operator-selection variables
|
||||
- Upgrade, downgrade, and removal behavior
|
||||
- Ansible dependency, validation, and test strategy
|
||||
- Collection bootstrap and end-to-end validation details beyond the locked
|
||||
dependency and testing policies above
|
||||
|
||||
@@ -1,134 +1,71 @@
|
||||
# Feature 0002 Remediation Review
|
||||
# Feature 0005 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.
|
||||
Reviewed implementation commits:
|
||||
|
||||
## Finding 1: Correct the Declared Role License
|
||||
- `3be78d8 Install and configure Narratio`
|
||||
- `0e8ad9f Add focused Narratio integration coverage`
|
||||
|
||||
Severity: medium
|
||||
Remediation commit:
|
||||
|
||||
`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.
|
||||
- `7feff47 Clean up Narratio review findings`
|
||||
|
||||
### Required Remediation
|
||||
The production role implements the targeted architecture, and the complete
|
||||
integration suite passes. The findings were limited to residual documentation
|
||||
and test-quality issues; no production task, template, default, argument
|
||||
specification, metadata, or dependency required a change.
|
||||
|
||||
- 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 1: Remove the Retained Placeholder README Sentence
|
||||
|
||||
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.
|
||||
`ansible-role-narratio/README.md` ended with the original placeholder sentence,
|
||||
“Ansible role to install the Narratio D&D transcript and session report
|
||||
generation suite.” The rewritten README already provided the complete role
|
||||
description, so this was accidental residue from the initial repository.
|
||||
|
||||
### 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.
|
||||
The retained placeholder sentence was removed without changing the substantive
|
||||
role documentation.
|
||||
|
||||
### Validation
|
||||
|
||||
- The README accurately describes package/Snap effects and managed filesystem
|
||||
paths.
|
||||
- The description agrees with `tests/integration` and the role defaults.
|
||||
|
||||
## Finding 3: Complete Binary-Type Verification
|
||||
## Finding 2: Make the Composition Test Non-vacuous
|
||||
|
||||
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.
|
||||
`ansible-role-narratio/tests/representative.yml` claimed to exercise
|
||||
caller-side composition, but both secondary fragments were empty. The verifier
|
||||
consequently proved only that one original entry survived serialization.
|
||||
|
||||
### Required Remediation
|
||||
### Resolution
|
||||
|
||||
- Add an assertion for `audita_binary_metadata.stat.isreg` to the existing
|
||||
binary metadata check.
|
||||
- Do not add another probe or production task.
|
||||
The Scriptorium artifact map now combines two nonempty caller-defined
|
||||
fragments, and the verifier checks one entry from each. Publish outputs use one
|
||||
direct value so the suite retains only one representative composition case.
|
||||
Native validation and the immediate clean repeat remain in place.
|
||||
|
||||
### 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
|
||||
## Finding 3: Use Ansible Privilege Escalation Directly in Verifiers
|
||||
|
||||
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.
|
||||
Both configuration verifiers escalated to root and then executed
|
||||
`/usr/bin/sudo -u narratio` inside `ansible.builtin.command`, creating a
|
||||
redundant second privilege transition.
|
||||
|
||||
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.
|
||||
### Resolution
|
||||
|
||||
### Required Remediation
|
||||
Both verifier tasks now use `become_user: narratio` and invoke Narratio
|
||||
directly. The integration driver enables pipelining and uses `/tmp` for
|
||||
Ansible's transient module area, avoiding the local controller's otherwise
|
||||
unmet temporary-file ACL requirement without adding a nested sudo command.
|
||||
|
||||
- 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.
|
||||
## Final Validation
|
||||
|
||||
### 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.
|
||||
`bash -n tests/integration`, the complete `tests/integration` suite, and
|
||||
`git diff --check` passed after remediation. Syntax checking and
|
||||
production-profile lint passed within the integration entry point. Baseline,
|
||||
missing-binary recovery, and representative-configuration scenarios passed
|
||||
their native Narratio checks as the application account, every required
|
||||
immediate repeat reported `changed=0` and `failed=0`, and cleanup restored the
|
||||
usable baseline deployment. No unresolved Feature 0005 findings remain.
|
||||
|
||||
282
docs/roadmap/test-suite-audit-findings.md
Normal file
282
docs/roadmap/test-suite-audit-findings.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# Test Suite Audit Findings
|
||||
|
||||
Status: resolved
|
||||
|
||||
## Executive Summary
|
||||
|
||||
All three integration suites pass, and each includes the most important common
|
||||
behavioral check: an immediate repeated role application reports no changes.
|
||||
The suites also contain useful coverage of explicitly selected releases,
|
||||
caller-supplied Go executables, missing-binary recovery, configuration
|
||||
rendering, native configuration validation, and Notarius pipeline composition.
|
||||
|
||||
The suites are nevertheless substantially larger and more implementation-bound
|
||||
than the workspace testing policy permits. The recurring problems are:
|
||||
|
||||
- exact assertions about the current default release and its commit;
|
||||
- independent verification of ownership, permissions, checkout state, and
|
||||
template output already managed by trusted Ansible modules;
|
||||
- parsing Ansible output for specific task names and individual
|
||||
`changed`/`skipped` results;
|
||||
- deliberate metadata drift followed by tests of `ansible.builtin.file`;
|
||||
- three-case negative tests of self-evident platform assertions;
|
||||
- repeated clean-run assertions after nearly every scenario; and
|
||||
- duplicated final shell assertions after equivalent Ansible verifiers.
|
||||
|
||||
The appropriate remediation is subtraction and consolidation. The retained
|
||||
suites should exercise stable role-owned behavior through final application
|
||||
outcomes, with one representative case for each meaningful behavior.
|
||||
|
||||
## Baseline
|
||||
|
||||
The audit ran on Ubuntu 26.04 `x86_64` with Ansible Core 2.21.3 and
|
||||
ansible-lint 26.8.0. The role revisions were:
|
||||
|
||||
| Repository | Revision | Integration result |
|
||||
| --- | --- | --- |
|
||||
| `ansible-role-seriatim` | `fb8dc41` | Pass |
|
||||
| `ansible-role-audita` | `847c4c3` | Pass |
|
||||
| `ansible-role-notarius` | `eb4f511` | Pass |
|
||||
|
||||
The following commands all exited successfully:
|
||||
|
||||
```text
|
||||
(cd ansible-role-seriatim && tests/integration)
|
||||
(cd ansible-role-audita && tests/integration)
|
||||
(cd ansible-role-notarius && tests/integration)
|
||||
```
|
||||
|
||||
Each driver installed its pinned collection requirements into a private
|
||||
temporary directory, ran a syntax check and production-profile ansible-lint,
|
||||
executed its behavioral scenarios, and restored its default deployment during
|
||||
cleanup. The runs emitted non-fatal local-tooling warnings about Python
|
||||
interpreter discovery or an already installed duplicate collection; these did
|
||||
not affect the results or any classification below.
|
||||
|
||||
All three role repositories were clean before and after the audit. The control
|
||||
repository began dirty solely because the new testing convention, audit plan,
|
||||
and status update were awaiting commit.
|
||||
|
||||
## Test Inventory
|
||||
|
||||
| Repository | Entry point and supporting files |
|
||||
| --- | --- |
|
||||
| `ansible-role-seriatim` | `tests/integration`, `tests/inventory`, `tests/converge.yml`, `tests/verify.yml`, `tests/unsupported.yml`, `collections/requirements.yml`, and the README validation section |
|
||||
| `ansible-role-audita` | `tests/integration`, `tests/inventory`, `tests/converge.yml`, `tests/verify.yml`, `tests/verify-config.yml`, `tests/unsupported.yml`, `collections/requirements.yml`, and the README validation section |
|
||||
| `ansible-role-notarius` | `tests/integration`, `tests/inventory`, `tests/converge.yml`, `tests/verify.yml`, `tests/verify-config.yml`, `tests/unsupported.yml`, `collections/requirements.yml`, and the README validation section |
|
||||
|
||||
## Cross-Repository Findings
|
||||
|
||||
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| All three | Pinned collection installation, syntax check, and ansible-lint | Static validity and reproducible dependencies | Retain | Keep as static validation before behavioral scenarios. | These checks complement rather than duplicate behavioral testing. |
|
||||
| All three | `require_clean_recap` after an immediate repeat | Role-level repeated convergence | Retain | Keep at least one immediate clean repeat per role and repeats specifically required after missing-binary recovery. | Overall `changed=0` is a first-class public role outcome. |
|
||||
| All three | `require_changed_recap` after each mutating setup | Ansible reports some change on the first run | Remove | Stop asserting a nonzero aggregate change count except where a future requirement specifically makes reporting itself significant. | Final application state is the behavior of interest; these checks add little beyond successful convergence and make scenario sequencing brittle. |
|
||||
| All three | Greps for named build, metadata, and configuration tasks | Current task names and individual `changed` or `skipped` results | Remove | Delete all task-output parsing. | These are direct implementation traces and fail under behavior-preserving task refactors. |
|
||||
| All three | Binary/source/configuration ownership and mode assertions | Postconditions declared to `file`, `git`, and `template` | Remove | Delete independent metadata and recursive-ownership verification. | These tests re-prove trusted module behavior rather than role-authored decisions. |
|
||||
| All three | Binary mode mutation followed by convergence | `ansible.builtin.file` repairs mode drift without building | Remove | Delete the scenario. | It is a focused regression test for the built-in file module and current task arrangement. |
|
||||
| All three | Debian, old Ubuntu, and unsupported-architecture matrix | Straightforward platform assertion branches | Remove | Delete `tests/unsupported.yml` and the three-case driver loop. | The declarative assertion is self-evident and does not warrant a negative matrix. |
|
||||
| All three | Restoration of the current default followed by verification and another repeat | Test cleanup and the current default identity | Simplify | Keep one best-effort cleanup convergence, but do not treat it as another test or assert the restored release value. | Cleanup is useful; testing a mutable default and repeating already established idempotence are not. |
|
||||
| All three | Final shell assertions duplicating earlier verifiers | Current commit, metadata, version, or config state | Remove | Delete duplicate end-of-driver assertions. | They add maintenance cost without protecting a distinct behavior. |
|
||||
|
||||
## Seriatim Classification
|
||||
|
||||
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Seriatim | Default convergence | The role can be applied with its default interface | Retain | Keep as a smoke test without asserting the exact default tag, commit, or filesystem metadata. | A default invocation is useful even though the present default value is not a stable test expectation. |
|
||||
| Seriatim | Default `v1.5.0` and commit verification | Present default release identity | Remove | Remove the fixed `default_commit` and exact default-version assertions. | This is a change detector; advancing the supported default should not break unrelated tests. |
|
||||
| Seriatim | Baseline immediate repeat | Clean convergence | Retain | Keep the overall `changed=0`, `failed=0` check. | This directly expresses the agreed idempotence requirement. |
|
||||
| Seriatim | Missing binary | The imperative build runs when its output is absent and then converges | Simplify | Delete the binary, apply the role, verify the executable through `--version`, and require the next run to be clean; remove task-name greps. | The binary-existence trigger is role-authored behavior, while the current task name and status are not. |
|
||||
| Seriatim | Dependency opt-out and custom Go executable | The caller-supplied build executable is honored | Simplify | Retain the wrapper invocation evidence, preferably combined with the missing-binary scenario; remove build-task greps and fixed-default assertions. | The selected build executable is a public role choice that cannot be observed reliably from the final binary alone. |
|
||||
| Seriatim | Binary metadata repair | Built-in file convergence | Remove | Delete the complete scenario. | It tests `ansible.builtin.file`, not Seriatim-specific behavior. |
|
||||
| Seriatim | Explicit `v1.4.0` selection | A caller-selected immutable release is installed | Simplify | Retain explicit `seriatim_version: v1.4.0` and verify `seriatim version v1.4.0`; remove the expected commit and task-state assertions. | This is the stable version-selection test described by the testing convention. |
|
||||
| Seriatim | Restore `v1.5.0` default | Cleanup plus present default identity | Simplify | Reduce to cleanup only. | Exact current-default verification duplicates the harmful baseline snapshot. |
|
||||
| Seriatim | Platform failure matrix | Distribution, release, and architecture assertions | Remove | Delete the matrix and `tests/unsupported.yml`. | No plausible role regression justifies separately testing each simple assertion. |
|
||||
| Seriatim | `tests/verify.yml` installation contract | Commit, source metadata, binary metadata, and version | Replace | Replace the broad verifier with a narrow native version check used for an explicitly selected tag. | Only the application outcome is valuable; the remaining assertions repeat trusted modules. |
|
||||
| Seriatim | README validation claims | Description of the current large matrix | Replace | Describe the lean retained behaviors after remediation. | Documentation should not promise deleted implementation-trace and module tests. |
|
||||
|
||||
## Audita Classification
|
||||
|
||||
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Audita | Default convergence | The role installs and configures successfully through its default interface | Retain | Keep as a smoke test and validate the resulting configuration with Audita; do not inspect exact default identity or metadata. | Successful native validation is an application outcome and does not freeze the default document. |
|
||||
| Audita | Default commit assertion | Present default checkout identity | Remove | Delete `default_commit` and exact commit verification. | It is both a mutable-default snapshot and a re-test of `ansible.builtin.git`. |
|
||||
| Audita | Source, binary, and configuration metadata | Trusted module postconditions | Remove | Delete the ownership, permission, regular-file, and executable assertions. | The role directly declares these states with trusted modules. |
|
||||
| Audita | Exact minimal default document `{"version": 1}` | Current default rendering | Remove | Do not snapshot the complete default document. Test null omission with explicitly supplied inputs in a representative configuration case instead. | A future intentional concrete default would otherwise cause an unrelated failure. |
|
||||
| Audita | Native validation of the managed configuration | The role produces configuration Audita accepts | Retain | Keep one native validation for default smoke coverage and one for the representative explicit configuration. | This observes application behavior rather than reconstructing its schema. |
|
||||
| Audita | Baseline immediate repeat | Clean convergence | Retain | Keep one role-level clean repeat. | This is required public behavior. |
|
||||
| Audita | Missing binary | Absent build output is recreated and convergence resumes | Simplify | Retain recovery and the following clean repeat; prove usability with the Audita CLI and remove task-output greps. | The imperative build trigger is role logic, but its task name is not. |
|
||||
| Audita | Dependency opt-out and custom Go executable | Caller-selected compiler path is used | Simplify | Retain wrapper invocation evidence and combine it with missing-binary recovery; remove task greps and redundant repeat runs. | This covers a documented public choice with one representative case. |
|
||||
| Audita | Binary metadata repair | Built-in file convergence | Remove | Delete the complete scenario. | It tests Ansible's file module. |
|
||||
| Audita | Representative configuration containing nearly every field | Field-to-YAML mapping, nested sections, and native validity | Simplify | Use a smaller explicit sample spanning representative scalar, list, nested, and duration shapes. Assert only selected paths and specifically selected omissions, then run native validation. | Full-document equality across nearly every field unnecessarily ossifies the template and public interface. |
|
||||
| Audita | Explicit falsey configuration | Empty lists and strings are rendered rather than omitted | Retain | Keep representative falsey values, preferably in the same explicit configuration scenario, and assert only the affected paths. | The null-versus-falsey distinction is role-authored and easy to regress. |
|
||||
| Audita | Configuration task changed while build task skipped | Configuration changes independently of installation | Remove | Delete task-name and status inspection. Confirm the rendered application behavior and successful convergence instead. | Whether named tasks ran is an implementation detail; the ordinary `when` expressions are suitable for review and lint. |
|
||||
| Audita | Restore the minimal default configuration | Cleanup and exact current default | Simplify | Keep restoration only as cleanup and remove fixed-document, fixed-commit, task-state, and extra repeat assertions. | It does not add a distinct stable behavior. |
|
||||
| Audita | Alternate raw commit `46b7356...` | A non-default Git revision can be selected | Replace | Remove the raw-commit case. Add an explicit immutable-release test only when Audita exposes a stable native way to identify the installed application release. | A raw source commit checked with `git rev-parse` tests checkout mechanics, not the installed application's release. Audita currently has no `--version` or `version` command, and tags `v0.9.0` and `v0.9.1` both resolve to `a84941d...`, so neither tag provides a distinguishable installed outcome today. |
|
||||
| Audita | Platform failure matrix | Straightforward platform assertions | Remove | Delete the matrix and `tests/unsupported.yml`. | This is expressly outside the testing house style. |
|
||||
| Audita | Final commit, metadata, and config checks | Duplicate checkout/module/validation assertions | Remove | Delete them. | Equivalent checks already ran, and most should themselves be removed. |
|
||||
| Audita | `tests/verify.yml` broad installation contract | Commit, metadata, default document, and native config validity | Replace | Reduce it to native configuration validation; move explicit field assertions to the focused representative verifier. | Only native validity is a stable application outcome in this verifier. |
|
||||
| Audita | README validation claims | Description of default, metadata, rebuild, and platform tests | Replace | Describe only the retained static checks and behavioral scenarios. | The present prose promises low-value coverage that should be removed. |
|
||||
|
||||
### Audita Version-Coverage Gap
|
||||
|
||||
The current suite does not—and with the present application interface cannot—
|
||||
perform the useful test “select immutable release X and verify that the
|
||||
installed Audita reports X.” Running either `audita --version` or
|
||||
`audita version` fails as an unknown command. The recommended role-test
|
||||
remediation is to remove the misleading raw-commit scenario rather than
|
||||
replace it with another Git-module assertion. A native Audita release-identity
|
||||
command would enable the desired explicit-version test later, but adding that
|
||||
application feature is outside this audit and should be selected separately.
|
||||
|
||||
## Notarius Classification
|
||||
|
||||
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Notarius | Default convergence | The default public interface installs and configures successfully | Retain | Keep as a smoke test, run `notarius --version` without fixing its output to the current default, and validate the configuration natively. | This proves the default path remains usable without snapshotting its values. |
|
||||
| Notarius | Default `v0.6.0` and commit verification | Present default release identity | Remove | Delete fixed `default_commit` and exact default-version assertions. | These fail solely when the supported default advances. |
|
||||
| Notarius | Source, binary, and configuration metadata | Trusted module postconditions | Remove | Delete ownership, mode, and regular-file assertions. | They re-test `git`, `file`, and `template`. |
|
||||
| Notarius | Exact minimal default document `{"version": 4}` | Current default rendering | Remove | Do not snapshot the default document. Supply `notarius_config_version` explicitly in the representative case and make any omission assertions about explicitly null inputs. | This preserves schema-bound behavior without turning future defaults into failures. |
|
||||
| Notarius | Native version command and configuration validation | Installed CLI is usable and accepts the managed configuration | Retain | Keep both native interfaces, but assert an exact version only in the explicitly selected release scenario. | These are application-level outcomes. |
|
||||
| Notarius | Baseline immediate repeat | Clean convergence | Retain | Keep one overall clean repeat. | This directly enforces the idempotence requirement. |
|
||||
| Notarius | Missing binary | The required output is rebuilt and then converges | Simplify | Retain artifact removal, native CLI verification, and the following clean repeat; remove task greps. | Missing-output recovery is role logic needed around the imperative build. |
|
||||
| Notarius | Dependency opt-out and custom Go executable | The caller-selected build executable is honored | Simplify | Keep wrapper invocation evidence and combine with missing-binary recovery; remove task greps and redundant repetitions. | This is meaningful configurable behavior with no better final-state discriminator. |
|
||||
| Notarius | Binary metadata repair | Built-in file convergence | Remove | Delete the complete scenario. | It tests trusted module behavior. |
|
||||
| Notarius | Explicit `v0.5.0` selection | A caller-selected immutable tag becomes the installed application | Simplify | Retain `notarius_version: v0.5.0` and exact native output `notarius v0.5.0`; remove expected commit and task-state assertions. | This remains useful after the role's default changes. |
|
||||
| Notarius | Restore `v0.6.0` default | Cleanup and present default identity | Simplify | Reduce to cleanup only. | It is not a distinct stable behavioral test. |
|
||||
| Notarius | Representative configuration | Field mapping, nested sections, pipelines, and validity | Simplify | Use a smaller set of explicit values and assert only those paths plus specifically selected null omissions; retain native validation. | Exact equality for a large complete document is broader and more brittle than the behavior requires. |
|
||||
| Notarius | Separate `profile_dir` case | One simple optional leaf mapping | Remove | Do not maintain a standalone scenario; a future representative case may select one profile source if it adds value. | The direct conditional and serialization are self-evident and already represented by other optional fields. |
|
||||
| Notarius | Separate `profile_file` case | A second simple optional leaf mapping | Remove | Delete the standalone scenario. | It duplicates the shape and risk of the profile-directory case without protecting a distinct likely regression. |
|
||||
| Notarius | Explicit falsey values | Zero, false, empty mapping, and empty string survive rendering | Retain | Fold representative falsey values into the focused configuration scenario and assert only those paths. | Null-versus-falsey behavior is a deliberate role invariant. |
|
||||
| Notarius | Caller-side pipeline composition | Independently defined mappings can be combined and passed through intact | Retain | Keep composition through ordinary `combine`, assert the two resulting pipeline entries, and run native validation; fold it into the representative configuration scenario if clarity permits. | This is an expressly selected public boundary and a plausible integration regression. |
|
||||
| Notarius | Configuration task changed while build task skipped | Configuration changes without rebuilding | Remove | Delete `require_configuration_change_without_build` and all task-trace greps. Verify final configuration, CLI usability, and clean repeat instead. | Task execution is not a stable public interface. |
|
||||
| Notarius | Restore the minimal default configuration | Cleanup plus mutable default assertions | Simplify | Keep cleanup only; remove exact default document, version, commit, task-state, and extra repeat checks. | The behavioral assertions duplicate change detectors elsewhere. |
|
||||
| Notarius | Platform failure matrix | Straightforward platform assertions | Remove | Delete the matrix and `tests/unsupported.yml`. | It provides no proportionate role-specific value. |
|
||||
| Notarius | Final commit, metadata, version, and config checks | Duplicate assertions | Remove | Delete them. | They repeat earlier verification and freeze the current default. |
|
||||
| Notarius | `tests/verify.yml` broad installation contract | Commit, metadata, default document, version, and validity | Replace | Reduce to native CLI smoke and configuration validation, with exact version verification only for an explicit tag. | This retains application outcomes while removing module tests and mutable snapshots. |
|
||||
| Notarius | README validation claims | Description of the current broad suite | Replace | Rewrite after simplification to describe the retained behavior. | Documentation should match the lean suite rather than preserve obsolete coverage promises. |
|
||||
|
||||
## Proposed Lean Target Suites
|
||||
|
||||
### Seriatim
|
||||
|
||||
1. Install pinned collections, syntax-check the convergence play, and lint the
|
||||
role and retained test files.
|
||||
2. Apply the role with defaults as a smoke test and immediately require a clean
|
||||
repeat, without asserting the current default tag or commit.
|
||||
3. Select `v1.4.0` explicitly and verify native output
|
||||
`seriatim version v1.4.0`.
|
||||
4. Delete the binary, supply a wrapper through `seriatim_go_binary` with
|
||||
dependency management disabled, converge, verify that the wrapper was used
|
||||
and the installed CLI works, then require a clean repeat.
|
||||
5. Restore defaults as cleanup without treating the restored value as a test
|
||||
expectation.
|
||||
|
||||
### Audita
|
||||
|
||||
1. Install pinned collections, syntax-check the convergence play, and lint the
|
||||
role and retained test files.
|
||||
2. Apply the role with defaults, validate the managed configuration with
|
||||
Audita, and immediately require a clean repeat. Do not assert the complete
|
||||
default document or current source identity.
|
||||
3. Apply one representative explicit configuration spanning nested, list,
|
||||
scalar, duration, falsey, and explicit-null behavior. Assert only the
|
||||
selected paths and omissions, validate it with Audita, and require a clean
|
||||
repeat.
|
||||
4. Delete the binary, supply a logging wrapper through `audita_go_binary` with
|
||||
dependency management disabled, converge, verify wrapper use and CLI
|
||||
usability, then require a clean repeat.
|
||||
5. Omit version-selection coverage until Audita exposes a native release
|
||||
identity; do not substitute a raw-commit checkout test.
|
||||
6. Restore defaults as cleanup only.
|
||||
|
||||
### Notarius
|
||||
|
||||
1. Install pinned collections, syntax-check the convergence play, and lint the
|
||||
role and retained test files.
|
||||
2. Apply the role with defaults, exercise `notarius --version`, validate the
|
||||
managed configuration, and immediately require a clean repeat without
|
||||
asserting the current default values.
|
||||
3. Select `v0.5.0` explicitly and verify native output `notarius v0.5.0`.
|
||||
4. Delete the binary, supply a logging wrapper through `notarius_go_binary`
|
||||
with dependency management disabled, converge, verify wrapper use and CLI
|
||||
usability, then require a clean repeat.
|
||||
5. Apply one representative explicit configuration that includes selected
|
||||
nested values, explicit falsey and null values, and two caller-composed
|
||||
pipeline mappings. Assert only those behaviors, validate the file with
|
||||
Notarius, and require a clean repeat.
|
||||
6. Restore defaults as cleanup only.
|
||||
|
||||
## Documentation Follow-up
|
||||
|
||||
The README validation sections in all three role repositories should be
|
||||
rewritten with their test harnesses. They currently advertise current-default,
|
||||
metadata, task-arrangement, and platform-guard coverage recommended for
|
||||
removal.
|
||||
|
||||
The durable feature roadmaps may continue to record the selected default tags,
|
||||
paths, ownership, permissions, and platform support as feature requirements.
|
||||
Those requirements need not each have a dedicated integration assertion.
|
||||
Test-specific roadmap language should, however, be corrected as follows:
|
||||
|
||||
- Feature 0001 and Feature 0003 should describe exact native version checks as
|
||||
checks of an explicitly selected immutable tag, not the current default.
|
||||
- Feature 0002 currently says repository-local tests execute Audita to verify
|
||||
its installed version. That is not implementable with Audita's current CLI
|
||||
and should be replaced with the limitation and follow-up described above.
|
||||
- Platform support remains part of each role contract, but the roadmaps should
|
||||
not imply that each straightforward assertion requires a negative matrix.
|
||||
|
||||
## Recommended Remediation Order
|
||||
|
||||
1. Simplify the Seriatim driver and verifier, remove its unsupported-platform
|
||||
playbook, and update its README.
|
||||
2. Simplify Audita's driver and verifiers, consolidate its configuration case,
|
||||
remove its unsupported-platform playbook, and update its README.
|
||||
3. Simplify Notarius's driver and verifiers, consolidate configuration and
|
||||
pipeline coverage, remove its unsupported-platform playbook, and update its
|
||||
README.
|
||||
4. Correct the test-specific language in the three feature roadmaps.
|
||||
5. Run all three complete integration entry points and confirm every role
|
||||
repository remains clean after its cleanup path.
|
||||
|
||||
No shared test abstraction is recommended. The three shell drivers have
|
||||
similar mechanics, but keeping each suite local and readable is worth the
|
||||
small amount of duplication, and a shared helper would create cross-repository
|
||||
coupling for little present benefit.
|
||||
|
||||
## Audit Completion
|
||||
|
||||
Every materially distinct implemented scenario has been classified above. The
|
||||
recommended removals either duplicate retained application-level coverage or
|
||||
exercise behavior owned by trusted Ansible modules or straightforward
|
||||
assertions. The lean targets retain default smoke coverage, immediate clean
|
||||
convergence, imperative missing-output recovery, caller-supplied build tooling,
|
||||
explicit release selection where natively observable, and representative
|
||||
configuration behavior.
|
||||
|
||||
The audit made no changes to production roles or test implementations.
|
||||
|
||||
## Remediation Status
|
||||
|
||||
The recommended remediation was implemented and independently reviewed. No
|
||||
production role behavior changed. The role commits are:
|
||||
|
||||
| Repository | Remediation commit | Final integration result |
|
||||
| --- | --- | --- |
|
||||
| `ansible-role-seriatim` | `e08c63c` | Pass |
|
||||
| `ansible-role-audita` | `d2d0b9d` | Pass |
|
||||
| `ansible-role-notarius` | `cfecf37` | Pass |
|
||||
|
||||
Final sequential validation on the approved Ubuntu 26.04 `x86_64` proxy ran
|
||||
each repository's `tests/integration` entry point successfully. Each cleanup
|
||||
path restored the default deployment, and the role repositories were clean
|
||||
after their remediation commits. The existing classifications remain the
|
||||
authoritative rationale for this implemented suite shape.
|
||||
|
||||
Independent review found no remaining code-quality issues or implementation
|
||||
gaps. The three complete integration entry points passed again sequentially;
|
||||
Bash syntax validation and `git diff --check` passed; native application checks
|
||||
confirmed that cleanup restored usable default deployments; and every
|
||||
repository in the workspace remained clean. No additional remediation record
|
||||
was required.
|
||||
192
docs/roadmap/test-suite-audit.md
Normal file
192
docs/roadmap/test-suite-audit.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# Test Suite Audit Plan
|
||||
|
||||
Status: complete
|
||||
|
||||
## Objective
|
||||
|
||||
Audit the implemented integration tests for the three completed standalone
|
||||
roles against the workspace's classical, state-based testing policy. The audit
|
||||
will identify tests that protect stable role-owned behavior, tests that should
|
||||
be simplified or replaced, and tests whose maintenance cost exceeds their
|
||||
value.
|
||||
|
||||
This is a review plan, not authorization to change role code or test suites.
|
||||
Any proposed remediation will be reviewed before a separate implementation
|
||||
plan is prepared.
|
||||
|
||||
## Scope
|
||||
|
||||
The audit covers the test harnesses, playbooks, fixtures, inventories, and
|
||||
test-related documentation in:
|
||||
|
||||
- `ansible-role-seriatim`
|
||||
- `ansible-role-audita`
|
||||
- `ansible-role-notarius`
|
||||
|
||||
Production role tasks, defaults, templates, and metadata may be inspected when
|
||||
needed to determine whether a test protects public role behavior or merely
|
||||
repeats an implementation detail. They are not remediation targets during the
|
||||
audit.
|
||||
|
||||
The audit does not cover the proof-of-concept `rakestraw-ansible` role, the
|
||||
suite-level role, or the collection. Those projects do not form part of the
|
||||
three completed standalone-role test suites.
|
||||
|
||||
## Governing Standard
|
||||
|
||||
Apply the normative testing house style in `docs/testing.md`. In
|
||||
particular, the audit will favor tests that exercise the role through its
|
||||
public variables and inspect meaningful final application behavior. It will
|
||||
disfavor tests that:
|
||||
|
||||
- freeze current defaults or other intentionally changeable values;
|
||||
- assert task names, order, individual task status, or other execution traces;
|
||||
- independently re-prove the documented postconditions of trusted Ansible
|
||||
modules;
|
||||
- exhaustively exercise self-evident assertions or equivalent low-value
|
||||
combinations; or
|
||||
- duplicate another test without protecting a distinct requirement or
|
||||
plausible regression.
|
||||
|
||||
An immediate second convergence with no reported changes remains required for
|
||||
each role. An explicitly selected version may be verified through the
|
||||
application's native interface; the role's current default version may not be
|
||||
treated as a permanent expected value.
|
||||
|
||||
## Classification Rubric
|
||||
|
||||
Classify every behavioral test case, including each materially distinct case
|
||||
embedded in a shared playbook or shell harness, as one of the following:
|
||||
|
||||
- **Retain:** protects stable, role-owned behavior through an externally
|
||||
meaningful outcome.
|
||||
- **Simplify:** protects useful behavior but includes redundant assertions,
|
||||
duplicated setup, or implementation coupling that can be removed.
|
||||
- **Replace:** addresses a valid requirement through an unstable or indirect
|
||||
assertion and should be expressed as a state-based outcome instead.
|
||||
- **Remove:** tests a mutable default, trusted module behavior, an
|
||||
implementation trace, or behavior without a stated requirement or plausible
|
||||
regression.
|
||||
- **Add:** identifies a material role-owned behavior that currently lacks
|
||||
representative coverage.
|
||||
|
||||
Each classification must state the behavior at issue and the reason for the
|
||||
recommended action. File length, test count, and aesthetic preference are not
|
||||
sufficient reasons by themselves.
|
||||
|
||||
## Audit Record
|
||||
|
||||
Write the completed review to
|
||||
`docs/roadmap/test-suite-audit-findings.md`. Record each finding in a table with
|
||||
these fields:
|
||||
|
||||
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
The report must also provide a proposed lean target suite for each role and
|
||||
identify any shared harness behavior that should be made consistent across the
|
||||
three repositories. Recommendations to remove coverage must state whether the
|
||||
behavior remains covered elsewhere or why it does not warrant coverage.
|
||||
|
||||
## Stage 1: Establish the Baseline
|
||||
|
||||
1. Confirm that the workspace and all three role repositories begin clean.
|
||||
2. Inventory every test entry point, playbook, fixture, inventory, helper, and
|
||||
test-related README statement in scope.
|
||||
3. Run each existing integration entry point without modification:
|
||||
|
||||
```text
|
||||
(cd ansible-role-seriatim && tests/integration)
|
||||
(cd ansible-role-audita && tests/integration)
|
||||
(cd ansible-role-notarius && tests/integration)
|
||||
```
|
||||
|
||||
4. Record success or failure, the scenarios exercised, and any environmental
|
||||
assumptions needed to reproduce the result. A pre-existing failure is audit
|
||||
evidence, not permission to repair it during this stage.
|
||||
|
||||
Completion criterion: the report contains a reproducible baseline and a
|
||||
complete test inventory for all three roles.
|
||||
|
||||
## Stage 2: Audit Seriatim
|
||||
|
||||
1. Map every Seriatim test case to a documented public behavior or classify it
|
||||
as lacking one.
|
||||
2. Review version selection, caller-supplied build tooling, rebuild behavior,
|
||||
metadata handling, platform validation, and repeat convergence using the
|
||||
common rubric.
|
||||
3. Identify assertions that inspect Ansible execution details or separately
|
||||
verify state already owned by trusted modules.
|
||||
4. Propose the smallest representative Seriatim suite that preserves valuable
|
||||
regression protection.
|
||||
|
||||
Completion criterion: every Seriatim case is classified and the report states
|
||||
the proposed retained, revised, removed, and missing coverage.
|
||||
|
||||
## Stage 3: Audit Audita
|
||||
|
||||
1. Map every Audita test case to a documented public behavior or classify it
|
||||
as lacking one.
|
||||
2. Review explicit version selection, native application verification,
|
||||
configuration rendering, omission of null settings, preservation of falsey
|
||||
values, platform validation, and repeat convergence.
|
||||
3. Distinguish tests of the role's configuration decisions from tests that
|
||||
merely repeat `template`, `file`, `git`, or package-module guarantees.
|
||||
4. Propose the smallest representative Audita suite that preserves valuable
|
||||
regression protection.
|
||||
|
||||
Completion criterion: every Audita case is classified and the report states
|
||||
the proposed retained, revised, removed, and missing coverage.
|
||||
|
||||
## Stage 4: Audit Notarius
|
||||
|
||||
1. Map every Notarius test case to a documented public behavior or classify it
|
||||
as lacking one.
|
||||
2. Review explicit version selection, native application verification,
|
||||
optional configuration rendering, falsey values, caller-composed pipeline
|
||||
mappings, platform validation, and repeat convergence.
|
||||
3. Distinguish tests of role-authored mapping and rendering behavior from
|
||||
assertions about trusted module mechanics or the current implementation
|
||||
layout.
|
||||
4. Propose the smallest representative Notarius suite that preserves valuable
|
||||
regression protection.
|
||||
|
||||
Completion criterion: every Notarius case is classified and the report states
|
||||
the proposed retained, revised, removed, and missing coverage.
|
||||
|
||||
## Stage 5: Reconcile the Three Suites
|
||||
|
||||
1. Compare classifications across roles so equivalent patterns receive
|
||||
equivalent treatment, while preserving genuine application differences.
|
||||
2. Identify duplicated harness machinery, inconsistent terminology, and
|
||||
documentation that describes implementation details or mutable defaults as
|
||||
promised test behavior.
|
||||
3. Separate static validation such as syntax checking and linting from
|
||||
behavioral integration coverage.
|
||||
4. Produce a repository-by-repository remediation proposal ordered by value
|
||||
and dependency. Do not propose a shared abstraction unless it removes
|
||||
demonstrated duplication without obscuring the individual role suites.
|
||||
5. Confirm that the proposed target for every role still includes a default or
|
||||
representative convergence, an immediate clean second convergence, and
|
||||
focused coverage of each retained role-owned behavior.
|
||||
|
||||
Completion criterion: the findings report is internally consistent, gives a
|
||||
lean target suite for each repository, and contains enough detail to support a
|
||||
later implementation plan without leaving test-policy decisions to the
|
||||
executor.
|
||||
|
||||
## Audit Completion Criteria
|
||||
|
||||
The audit is complete when:
|
||||
|
||||
- every implemented behavioral case across all three repositories has an
|
||||
explicit classification and rationale;
|
||||
- baseline results and reproduction commands are recorded;
|
||||
- proposed removals do not silently discard coverage of a required public
|
||||
behavior;
|
||||
- proposed additions are limited to material role-owned behavior;
|
||||
- README and harness-documentation corrections are identified alongside test
|
||||
changes;
|
||||
- no production or test implementation has been changed during the audit; and
|
||||
- the findings have been reviewed before any remediation plan is written to
|
||||
`docs/roadmap/implementation.md`.
|
||||
@@ -1,10 +1,10 @@
|
||||
# Workspace Status
|
||||
|
||||
Last updated: 2026-09-08
|
||||
Last updated: 2026-09-10
|
||||
|
||||
Current milestone: MVP standalone application roles
|
||||
Current milestone: M1-03 suite-level pipeline role
|
||||
|
||||
Current focus: Select and define the next unit of work.
|
||||
Current focus: Review the staged Feature 0006 implementation plan.
|
||||
|
||||
| ID | Deliverable | Owner | State | Evidence or next step |
|
||||
| --- | --- | --- | --- | --- |
|
||||
@@ -13,12 +13,18 @@ Current focus: Select and define the next unit of work.
|
||||
| M0-03 | Tracked MVP roadmap | workspace | done | `docs/roadmap/mvp.md` established |
|
||||
| M0-04 | Aggregate repository status | workspace | done | `scripts/status` created |
|
||||
| M0-05 | Suite-level role repository | ansible-role-dnd-pipeline | done | Repository created and added to `workspace.yml` |
|
||||
| M1-01 | Remaining MVP design decisions | workspace | ready | Select the next design topic or application role |
|
||||
| M1-02 | Standalone application roles | role repositories | in_progress | Select the next standalone application role |
|
||||
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | proposed | Begin after standalone role interfaces stabilize |
|
||||
| M1-01 | Remaining MVP design decisions | workspace | done | Feature 0003 roadmap fixes the Notarius configuration interface |
|
||||
| M1-02 | Standalone application roles | role repositories | done | All five standalone roles implemented and independently reviewed |
|
||||
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | in_progress | Feature 0006 defines the dependency-composition foundation |
|
||||
| M1-04 | Collection assembly | ansible-collection-dnd | proposed | Select and implement the pipeline-role incorporation mechanism |
|
||||
| F0001 | Install Seriatim from pinned source | ansible-role-seriatim | done | Implementation, integration coverage, and final remediation completed through `fb8dc41` |
|
||||
| F0002 | Install and configure Audita | ansible-role-audita | done | Implementation and remediation completed through `3a8c21f`; full integration suite passed |
|
||||
| F0002 | Install and configure Audita | ansible-role-audita | done | Field-specific configuration completed in `e61f02f` and `847c4c3`; full suite passed |
|
||||
| F0003 | Install and configure Notarius | ansible-role-notarius | done | Implemented and validated through remediation commit `eb4f511` |
|
||||
| F0004 | Install and configure Scriptorium | ansible-role-scriptorium | done | Implemented and validated through remediation commit `8f47aa8` |
|
||||
| F0005 | Install and configure Narratio | ansible-role-narratio | done | Implemented and validated through remediation commit `7feff47` |
|
||||
| F0006 | Establish pipeline-role composition | ansible-role-dnd-pipeline | ready | Execute `docs/roadmap/implementation.md` after its review and dependency publication |
|
||||
| A0001 | Audit completed standalone-role test suites | workspace and standalone roles | done | Findings recorded in `docs/roadmap/test-suite-audit-findings.md` |
|
||||
| R0001 | Simplify completed standalone-role test suites | workspace and standalone roles | done | Role commits `e08c63c`, `d2d0b9d`, and `cfecf37` passed implementation and independent review |
|
||||
|
||||
## Updating This File
|
||||
|
||||
|
||||
47
docs/testing.md
Normal file
47
docs/testing.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Testing House Style
|
||||
|
||||
This policy is normative for creating, changing, reviewing, and auditing tests
|
||||
in this workspace.
|
||||
|
||||
- Use a classical state-based approach, also commonly described as Chicago or
|
||||
Detroit style. Exercise the real role through its public interface and
|
||||
observe the resulting deployed system.
|
||||
- Test behavior owned by the role, not the current arrangement of tasks that
|
||||
implements it. A useful test should normally remain valid after an internal
|
||||
refactor that preserves the same public behavior.
|
||||
- Require an immediate second role application to report no changes. Clean
|
||||
repeated convergence is a first-class role outcome, not a test of any one
|
||||
module.
|
||||
- Distinguish configurable behavior from current defaults. To prove version
|
||||
selection, explicitly request a version and verify that the application
|
||||
reports that version. Do not assert that the same version remains the role's
|
||||
default. For example, a useful test sets `audita_version: v0.9.0` and verifies
|
||||
that the installed Audita reports `v0.9.0`; a harmful test asserts that
|
||||
`v0.9.0` is the role's current default. The former continues to prove version
|
||||
selection after the default advances to `v0.10.0`, while the latter fails
|
||||
merely because of the intended update.
|
||||
- Use a default invocation as a smoke test when useful, but do not snapshot
|
||||
exact default values, selected commits, complete default configuration
|
||||
documents, or counts of default variables. Those assertions are change
|
||||
detectors that turn intentional updates into unrelated test failures.
|
||||
- Do not assert task names, task order, individual `changed` or `skipped`
|
||||
results, or other implementation traces. Inspect the final system and the
|
||||
overall clean-repeat result instead.
|
||||
- Do not test documented behavior of `ansible.builtin`, widely used
|
||||
`community.general`, or other trusted modules. In particular, do not
|
||||
independently verify file existence, ownership, permissions, package state,
|
||||
checkout state, or template deployment merely to repeat module arguments.
|
||||
- Test role-authored decisions only when they express meaningful public
|
||||
behavior. Examples include an explicitly selected application version, a
|
||||
caller-supplied build executable, configuration rendering with representative
|
||||
non-null and falsey values, and composition of caller-supplied mappings.
|
||||
- Verify application outcomes with the application's native interface when
|
||||
practical. Prefer executing the installed application or its configuration
|
||||
validator over reconstructing its rules in Ansible assertions.
|
||||
- Self-evident declarative guards, including straightforward platform
|
||||
assertions, do not require a negative test matrix.
|
||||
- Prefer one representative case for a behavior over exhaustive combinations.
|
||||
Every additional test must protect a requirement or a plausible regression,
|
||||
not merely increase coverage.
|
||||
- Keep syntax checking and linting as static validation. They complement the
|
||||
behavioral suite but do not justify tests that freeze implementation details.
|
||||
@@ -51,6 +51,18 @@ repositories:
|
||||
category: reference
|
||||
purpose: Existing deployment repository and pipeline_dnd proof of concept
|
||||
|
||||
- name: campaigns
|
||||
path: assets/campaigns
|
||||
remote: https://gitea.maximumdirect.net/eric/campaigns.git
|
||||
category: content
|
||||
purpose: D&D campaign registry content deployed by the pipeline role
|
||||
|
||||
- name: narratio-prompts
|
||||
path: assets/narratio-prompts
|
||||
remote: https://gitea.maximumdirect.net/eric/narratio-prompts.git
|
||||
category: content
|
||||
purpose: PromptKit-compatible prompts and schemas deployed for Scriptorium
|
||||
|
||||
- name: narratio
|
||||
path: ../narratio
|
||||
remote: https://gitea.maximumdirect.net/eric/narratio.git
|
||||
@@ -80,9 +92,3 @@ repositories:
|
||||
remote: https://gitea.maximumdirect.net/eric/scriptorium.git
|
||||
category: application
|
||||
purpose: Scriptorium source and authoritative application contracts
|
||||
|
||||
- name: narratio-prompts
|
||||
path: ../narratio-prompts
|
||||
remote: https://gitea.maximumdirect.net/eric/narratio-prompts.git
|
||||
category: content
|
||||
purpose: PromptKit-compatible pipeline prompt library
|
||||
|
||||
Reference in New Issue
Block a user