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-scriptorium/
|
||||||
/ansible-role-seriatim/
|
/ansible-role-seriatim/
|
||||||
/rakestraw-ansible/
|
/rakestraw-ansible/
|
||||||
|
/assets/campaigns/
|
||||||
|
/assets/narratio-prompts/
|
||||||
|
|
||||||
# Local tool state.
|
# Local tool state.
|
||||||
/.codebase-memory/
|
/.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,
|
- Read [the workspace orientation](docs/orientation.md) before selecting,
|
||||||
inspecting, or modifying a repository. It maps the repositories and defines
|
inspecting, or modifying a repository. It maps the repositories and defines
|
||||||
the canonical sources of truth.
|
the canonical sources of truth.
|
||||||
- Read [the workspace conventions](docs/conventions.md) before reviewing or
|
- Read [the workspace conventions](docs/conventions.md) before making any
|
||||||
changing Ansible, preparing a feature roadmap or implementation plan, or
|
repository change. They define the workspace-wide rules and route work to
|
||||||
making any repository change. It defines the normative house style and
|
specialized policy.
|
||||||
working conventions.
|
- 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
|
- Read [the planning policy](docs/planning.md) before preparing a feature
|
||||||
roadmap or implementation plan or managing an ongoing work stream.
|
roadmap or implementation plan or managing an ongoing work stream.
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ only workspace documentation, planning, and shared development utilities.
|
|||||||
|
|
||||||
## Start Here
|
## Start Here
|
||||||
|
|
||||||
- [`AGENTS.md`](AGENTS.md) describes repository boundaries and working
|
- [`AGENTS.md`](AGENTS.md) describes repository boundaries and routes each
|
||||||
conventions.
|
kind of work to its required policy documents.
|
||||||
- [`workspace.yml`](workspace.yml) inventories the repositories used during
|
- [`workspace.yml`](workspace.yml) inventories the repositories used during
|
||||||
development.
|
development.
|
||||||
- [`docs/roadmap/mvp.md`](docs/roadmap/mvp.md) records settled MVP decisions
|
- [`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
|
# 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
|
- Confirm the target repository before editing; never treat this directory as
|
||||||
a monorepo.
|
a monorepo.
|
||||||
@@ -20,48 +31,3 @@
|
|||||||
run.
|
run.
|
||||||
- Do not duplicate an application contract in workspace documentation when a
|
- Do not duplicate an application contract in workspace documentation when a
|
||||||
link and a concise deployment consequence are sufficient.
|
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`.
|
suite-level role exposed by the collection as `rakestraw.dnd.pipeline`.
|
||||||
- `ansible-role-{narratio,notarius,audita,seriatim,scriptorium}`: standalone
|
- `ansible-role-{narratio,notarius,audita,seriatim,scriptorium}`: standalone
|
||||||
application roles.
|
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
|
- `rakestraw-ansible`: working deployment repository containing the
|
||||||
`pipeline_dnd` proof of concept; treat it as read-only reference unless the
|
`pipeline_dnd` proof of concept; treat it as read-only reference unless the
|
||||||
task explicitly includes it.
|
task explicitly includes it.
|
||||||
@@ -18,15 +22,17 @@ Relevant upstream repositories are siblings of this directory:
|
|||||||
|
|
||||||
- `../{narratio,notarius,audita,seriatim,scriptorium}`: application source and
|
- `../{narratio,notarius,audita,seriatim,scriptorium}`: application source and
|
||||||
authoritative application contracts.
|
authoritative application contracts.
|
||||||
- `../narratio-prompts`: pipeline prompt-library content.
|
|
||||||
|
|
||||||
Use [the workspace inventory](../workspace.yml) as the complete
|
Use [the workspace inventory](../workspace.yml) as the complete
|
||||||
machine-readable inventory of paths and remotes.
|
machine-readable inventory of paths and remotes.
|
||||||
|
|
||||||
## Sources of Truth
|
## Sources of Truth
|
||||||
|
|
||||||
- [Workspace conventions](conventions.md): normative working and Ansible house
|
- [Workspace conventions](conventions.md): normative workspace-wide rules and
|
||||||
style.
|
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
|
- [Planning policy](planning.md): normative feature planning and progress
|
||||||
workflow.
|
workflow.
|
||||||
- [MVP roadmap](roadmap/mvp.md): settled MVP scope, architecture, and open
|
- [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.
|
active staged plan or, when no plan is approved, a pending-plan notice.
|
||||||
- Application repositories: CLI, configuration, build, and integration
|
- Application repositories: CLI, configuration, build, and integration
|
||||||
contracts.
|
contracts.
|
||||||
|
- Asset repositories: authoritative campaign and prompt-library content and
|
||||||
|
layout.
|
||||||
- Individual Ansible repositories: implementation and repository-local tests.
|
- Individual Ansible repositories: implementation and repository-local tests.
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# Planning and Progress
|
# Planning and Progress
|
||||||
|
|
||||||
- Read and follow [the workspace conventions](conventions.md) before preparing
|
- 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
|
- Update [the MVP roadmap](roadmap/mvp.md) when a design question becomes a
|
||||||
settled scope or architecture decision.
|
settled scope or architecture decision.
|
||||||
- Discuss and select the next unit of work before planning implementation.
|
- 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
|
GPT-5.6-Terra to execute sequentially. Number stages with consecutive
|
||||||
integers beginning with `Stage 1`; do not skip numbers or use nested stage
|
integers beginning with `Stage 1`; do not skip numbers or use nested stage
|
||||||
numbering. Each stage must identify its repository, preconditions, required
|
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
|
- Resolve architectural choices during roadmap and plan review. Do not leave
|
||||||
unresolved design judgment to the implementation agent.
|
unresolved design judgment to the implementation agent.
|
||||||
- Update [workspace status](status.md) when cross-repository work starts,
|
- 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`.
|
it at `/usr/local/bin/seriatim`.
|
||||||
- Rebuild when the source checkout changes or the binary is absent.
|
- Rebuild when the source checkout changes or the binary is absent.
|
||||||
- Converge the installed binary to `root:root` ownership and mode `0755`.
|
- 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
|
- Keep the role interface, README, metadata, and focused local tests consistent
|
||||||
with the simplified behavior.
|
with the simplified behavior.
|
||||||
- Remove obsolete build-state files and implementation machinery from the
|
- 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.
|
- Detect arbitrary binary modification independently of reported version.
|
||||||
- Protect or recover from unexpected symbolic links and malformed managed
|
- Protect or recover from unexpected symbolic links and malformed managed
|
||||||
paths.
|
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
|
These are candidates for separately selected features if operational
|
||||||
experience or a changed threat model justifies them.
|
experience or a changed threat model justifies them.
|
||||||
|
|||||||
@@ -6,243 +6,245 @@ Status: done
|
|||||||
|
|
||||||
Provide a small, independently usable `rakestraw.audita` role that installs
|
Provide a small, independently usable `rakestraw.audita` role that installs
|
||||||
Audita from a pinned Git tag, builds its executable on the managed host, and
|
Audita from a pinned Git tag, builds its executable on the managed host, and
|
||||||
manages its versioned YAML configuration. Follow the module-driven Seriatim
|
offers an ergonomic field-specific interface for its versioned YAML
|
||||||
pattern while adding only the configuration behavior that distinguishes
|
configuration. Unspecified optional fields are omitted so Audita retains
|
||||||
Audita.
|
ownership of its application defaults.
|
||||||
|
|
||||||
## Problem or Opportunity
|
## Problem or Opportunity
|
||||||
|
|
||||||
The `ansible-role-audita` repository currently contains only its initial
|
The completed source-installation flow is concise and correct, but the initial
|
||||||
placeholder files. Audita needs a standalone installer before the suite role
|
configuration interface exposes only one `audita_config` mapping. That requires
|
||||||
can compose the transcript-processing pipeline and supply D&D-specific runtime
|
every caller to know and reproduce Audita's native nested schema, and it does
|
||||||
policy.
|
not provide the ordinary role ergonomics expected for inventory variables.
|
||||||
|
|
||||||
An earlier implementation direction depended on the superseded Seriatim
|
The role should expose documented variables for individual settings and render
|
||||||
fingerprint, sidecar-state, staged-build, and corruption-recovery architecture.
|
only values expressly selected by the caller. This permits straightforward
|
||||||
This roadmap replaces that direction with a concise implementation that trusts
|
`host_vars`, `group_vars`, play variables, and suite-role overrides while
|
||||||
Ansible modules, rebuilds only for required conditions, and keeps production
|
allowing upstream default changes to take effect automatically when a setting
|
||||||
role tasks separate from integration verification.
|
is not managed by Ansible.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
- Implement `ansible-role-audita` as a conventional standalone role.
|
- Retain the completed Ubuntu 26.04 `amd64` and `arm64` source installation.
|
||||||
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
|
- Retain default tag `v0.9.1`, Go Snap channel `1.26/stable`, source path
|
||||||
- Install Git and the official Go Snap with classic confinement when build
|
`/usr/local/src/audita`, and binary path `/usr/local/bin/audita`.
|
||||||
dependency management is enabled.
|
- Retain rebuild triggers of changed Git checkout or absent binary.
|
||||||
- Default the Go Snap channel to `1.26/stable`.
|
- Replace the complete `audita_config` mapping with typed, field-specific
|
||||||
- Check out immutable Audita tag `v0.9.1` by default under the root-owned path
|
configuration variables.
|
||||||
`/usr/local/src/audita`.
|
- Always render the required configuration schema version, defaulting to `1`.
|
||||||
- Build Audita with its upstream release build contract and install the native
|
- Define every optional configuration variable as `null` by default and omit
|
||||||
executable at `/usr/local/bin/audita`.
|
its YAML field when it remains null.
|
||||||
- Rebuild when the Git checkout changes or the binary is absent.
|
- Render nested YAML sections only when at least one setting in that section is
|
||||||
- Converge the installed binary to `root:root` ownership and mode `0755`.
|
non-null.
|
||||||
- Manage a versioned Audita YAML configuration at
|
- Manage `/usr/local/etc/audita/config.yml` from a Jinja template as
|
||||||
`/usr/local/etc/audita/config.yml`, owned by `root:root` with mode `0644`.
|
`root:root` mode `0644`.
|
||||||
- Default the managed configuration to the minimal valid mapping
|
- Keep defaults, argument specifications, template, README, metadata,
|
||||||
`{"version": 1}`, allowing Audita's own defaults to govern application
|
dependency declaration, and focused tests consistent with this contract.
|
||||||
behavior.
|
|
||||||
- Keep role defaults, argument specifications, README, metadata, dependency
|
|
||||||
declaration, and focused local tests consistent with this contract.
|
|
||||||
|
|
||||||
## Non-goals
|
## 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,
|
- D&D-specific model selection, concurrency, thresholds, transcript context,
|
||||||
or other suite policy. The suite-level role will provide those overrides.
|
or other suite policy.
|
||||||
- A separate Ansible variable for every field in Audita's configuration
|
- A parallel mapping-based configuration escape hatch or merge/precedence
|
||||||
schema.
|
rules between two configuration interfaces.
|
||||||
- API keys, secret values, environment files, or another secret-delivery
|
- API keys or other secret values. Variables may select environment-variable
|
||||||
mechanism. Configuration may name environment variables but must not contain
|
names, but the role does not manage their values.
|
||||||
their secret values.
|
- Creation of the `narratio` account or management of runtime, campaign,
|
||||||
- Creation or management of the `narratio` account, operator groups, campaign
|
glossary, transcript, diagnostics, or secret-delivery infrastructure.
|
||||||
data, glossaries, transcript data, or diagnostics directories.
|
- Services, scheduling, removal behavior, pipeline composition, prebuilt
|
||||||
- Installation or configuration of another pipeline application.
|
artifacts, or cross-compilation.
|
||||||
- Services, scheduling, removal behavior, or pipeline composition.
|
- Production execution of Audita for build or configuration validation.
|
||||||
- Prebuilt release artifacts or cross-compilation.
|
- Fingerprints, checksums, sidecar state, staged replacement, manual Git
|
||||||
- Production execution of Audita to validate the build or configuration.
|
cleanup, compiler inspection, or out-of-band drift detection.
|
||||||
- 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
|
## Target End State
|
||||||
|
|
||||||
On an Ubuntu 26.04 `amd64` or `arm64` host, applying the role with defaults
|
With no configuration overrides, the role writes the minimal valid document:
|
||||||
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`.
|
|
||||||
|
|
||||||
An immediate second application reports no changes. A changed Git checkout or
|
```yaml
|
||||||
missing binary causes one build; configuration changes converge through the
|
version: 1
|
||||||
ordinary file-management module without rebuilding Audita. Repository-local
|
```
|
||||||
tests execute the installed CLI to verify the build and validate the managed
|
|
||||||
configuration.
|
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
|
## Repository Ownership
|
||||||
|
|
||||||
- `ansible-role-audita` owns the role implementation, public interface,
|
- `ansible-role-audita` owns installation, the public configuration interface,
|
||||||
configuration rendering, metadata, dependency declaration, README, and
|
template, metadata, README, and repository-local tests.
|
||||||
repository-local validation.
|
- `../audita` is the read-only authority for build, CLI, configuration schema,
|
||||||
- `../audita` is the read-only authority for the build, CLI, and configuration
|
and application-default contracts.
|
||||||
contracts.
|
- `rakestraw-ansible` is a read-only style reference for field-specific role
|
||||||
- `rakestraw-ansible` is a read-only style and configuration-policy reference.
|
variables and conditional templates; its historical values are not
|
||||||
- `ansible-role-dnd-pipeline` will later own the D&D-specific values supplied
|
authoritative defaults.
|
||||||
through the standalone role's configuration interface.
|
- `ansible-role-dnd-pipeline` will later own D&D-specific overrides supplied
|
||||||
- `ansible-workspace-dnd` owns this roadmap, the eventual staged implementation
|
through the standalone role variables.
|
||||||
plan, and aggregate status.
|
- `ansible-workspace-dnd` owns this roadmap, the staged plan, and aggregate
|
||||||
|
status.
|
||||||
- All other repositories remain unchanged.
|
- All other repositories remain unchanged.
|
||||||
|
|
||||||
## Constraints and Settled Decisions
|
## Constraints and Settled Decisions
|
||||||
|
|
||||||
- The selected release is tag `v0.9.1`, which resolves to commit
|
- Tag `v0.9.1` resolves to
|
||||||
`a84941d68168a1ed9ea7423b6477ae8218be73f9`.
|
`a84941d68168a1ed9ea7423b6477ae8218be73f9` and retains the build contract
|
||||||
- Tags `v0.9.0` and `v0.9.1` resolve to the same commit, so `v0.9.0` cannot
|
already implemented and validated through role commit `3a8c21f`.
|
||||||
exercise checkout-change rebuilding. Focused integration may temporarily
|
- Audita's strict schema version is `1`; all other top-level fields are
|
||||||
select buildable commit `46b7356a3b54a2771ce9a617e4fa3e8d13728cac`
|
optional and overlay application defaults.
|
||||||
before restoring the default tag.
|
- `audita_config_version` names the schema version so `audita_version` remains
|
||||||
- The tag declares Go 1.24.0. The suite-standard Go Snap channel remains
|
unambiguously the selected application release.
|
||||||
`1.26/stable`.
|
- Optional variables are present in role defaults with YAML null values. This
|
||||||
- The upstream release build uses package
|
documents the interface and enables argument validation without emitting
|
||||||
`gitea.maximumdirect.net/eric/audita/cmd/audita`, `CGO_ENABLED=0`,
|
upstream defaults.
|
||||||
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags `-s -w -X
|
- Template conditions use `is not none`, not truthiness, so expressly supplied
|
||||||
gitea.maximumdirect.net/eric/audita/internal/buildinfo.Version=<version>`.
|
falsey values are rendered.
|
||||||
- Audita exposes no release-version command needed by production convergence.
|
- String and list values must be safely encoded as YAML values rather than
|
||||||
The role uses only checkout change and binary absence as build triggers.
|
interpolated with hand-written quoting.
|
||||||
- Audita configuration schema version `1` is strict. The native command
|
- A parent mapping is emitted only when at least one corresponding child value
|
||||||
`audita config validate --config <path>` reports `config is valid` for a
|
is non-null.
|
||||||
valid file and is used only by tests.
|
- The role does not validate Audita's semantic constraints during production
|
||||||
- Audita's default configuration search order prefers
|
convergence. Native validation remains integration-test behavior.
|
||||||
`/usr/local/etc/audita/config.yml` over `/etc/audita/config.yml`; the role
|
- Task-level `become: true`, `community.general` 13.3.0, and all existing
|
||||||
manages the preferred path.
|
installation decisions remain unchanged.
|
||||||
- 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.
|
|
||||||
|
|
||||||
## Fixed Public Interface
|
## Fixed Public Interface
|
||||||
|
|
||||||
| Variable | Default | Purpose |
|
Retain these installation variables:
|
||||||
| --- | --- | --- |
|
|
||||||
| `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 |
|
|
||||||
|
|
||||||
The package, build flags, linker symbol, environment values, file ownership,
|
| Variable | Default |
|
||||||
and file modes are fixed implementation details. The selected version is both
|
| --- | --- |
|
||||||
the Git revision and the value supplied to the upstream linker flag.
|
| `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
|
## Simplest Viable Implementation
|
||||||
|
|
||||||
The expected implementation is approximately nine ordinary tasks in one
|
Retain the existing nine-task installation flow. Make only these production
|
||||||
readable task file:
|
changes:
|
||||||
|
|
||||||
1. Assert Ubuntu 26.04 and architecture `x86_64` or `aarch64`.
|
1. Replace `audita_config` in defaults and argument specifications with the
|
||||||
2. Install Git with `ansible.builtin.apt`, including
|
field-specific variables above.
|
||||||
`cache_valid_time: 3600`, when dependency management is enabled.
|
2. Add `templates/config.yml.j2`, always rendering `version` and conditionally
|
||||||
3. Install the classic Go Snap from `audita_go_snap_channel` with
|
rendering every optional field and necessary parent mapping.
|
||||||
`community.general.snap` when dependency management is enabled.
|
3. Replace the final `ansible.builtin.copy` task with one
|
||||||
4. Create the source, binary, and configuration parent directories with one
|
`ansible.builtin.template` task using the existing destination, ownership,
|
||||||
`ansible.builtin.file` loop.
|
and mode.
|
||||||
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`.
|
|
||||||
|
|
||||||
Apply task-level privilege escalation only to tasks that require it. Use
|
Do not add configuration assembly facts, nested merge filters, validation
|
||||||
`argv` for the build command, and put its two conditions directly on the build
|
commands, preliminary file probes, or multiple configuration tasks. The
|
||||||
task. Do not add a rebuild fact, handler, handler flush, executable discovery,
|
template is the direct expression of the selected configuration state.
|
||||||
compiler interrogation, configuration preflight, or post-operation validation
|
|
||||||
to production tasks.
|
|
||||||
|
|
||||||
## Rationale and Alternatives
|
## Rationale and Alternatives
|
||||||
|
|
||||||
Audita's installation mechanics are intentionally the same as Seriatim's:
|
Field-specific variables are the ordinary ergonomic interface for inventory
|
||||||
declarative dependency and checkout management surrounding one imperative
|
and composing roles. Nullable defaults make that interface discoverable and
|
||||||
build command. The binary existence probe is justified because Ansible cannot
|
typed without freezing a duplicate copy of Audita's application defaults into
|
||||||
infer whether that command's output exists; no other build-state model is
|
Ansible. Conditional rendering also preserves the distinction between an
|
||||||
needed.
|
unset field and a caller intentionally supplying a falsey value.
|
||||||
|
|
||||||
A single configuration mapping is smaller and more durable than duplicating
|
Leaving variables entirely undefined would produce the same file but weaken
|
||||||
Audita's evolving schema as dozens of role variables. A minimal default mapping
|
interface documentation and argument validation. Section-level dictionaries
|
||||||
produces a valid configuration while preserving upstream defaults. The future
|
would shorten the template but require callers to understand more of the
|
||||||
suite role can supply its complete D&D-specific mapping without coupling the
|
native nested schema. Retaining `audita_config` beside field variables would
|
||||||
standalone role to one deployment.
|
require unneeded merge and precedence semantics. None is preferable to the
|
||||||
|
single field-specific interface.
|
||||||
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.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- Unsupported distributions, Ubuntu releases, and architectures fail before
|
- All existing source-installation and platform acceptance criteria continue
|
||||||
application state is modified.
|
to pass without production task-flow expansion.
|
||||||
- Default execution on the local Ubuntu 26.04 host installs or confirms Git
|
- Defaults and argument specifications contain exactly the eight installation
|
||||||
and Go and checks out Audita tag `v0.9.1` at commit
|
variables and thirty configuration variables in the Fixed Public Interface.
|
||||||
`a84941d68168a1ed9ea7423b6477ae8218be73f9`.
|
- No `audita_config` compatibility variable remains.
|
||||||
- The role builds with the fixed upstream contract and installs
|
- Default convergence writes a YAML mapping containing exactly `version: 1`.
|
||||||
`/usr/local/bin/audita` as `root:root` mode `0755`.
|
- Every optional field is absent when its variable is null.
|
||||||
- The managed source checkout is recursively owned by `root:root`.
|
- Setting a representative value in every configuration section renders the
|
||||||
- The default configuration is a valid schema-version `1` document at
|
correct nested native fields and passes `audita config validate`.
|
||||||
`/usr/local/etc/audita/config.yml`, owned by `root:root` with mode `0644`.
|
- Explicit falsey non-null values are rendered rather than omitted; semantic
|
||||||
- Repository-local tests successfully execute the installed CLI and receive
|
validity remains Audita's responsibility.
|
||||||
`config is valid` when validating the managed configuration.
|
- Configuration changes run the template task but not the build task and
|
||||||
- An immediate second role run reports no changes.
|
reach an unchanged immediate repeat.
|
||||||
- A missing binary causes one rebuild followed by an unchanged run.
|
- The installed configuration remains a regular file owned by `root:root`
|
||||||
- A changed checkout causes one rebuild followed by an unchanged run.
|
with mode `0644`.
|
||||||
- A configuration change updates only configuration state and does not rebuild
|
- Production tasks do not invoke Audita, inspect the existing configuration,
|
||||||
the binary.
|
or construct intermediate configuration state.
|
||||||
- Dependency opt-out accepts a caller-supplied `audita_go_binary`.
|
- The README documents each variable, null-as-unmanaged behavior, safe secret
|
||||||
- A play connecting as an ordinary sudo-capable user can apply the role without
|
environment-variable naming, and the distinction between application and
|
||||||
play-level privilege escalation.
|
suite defaults.
|
||||||
- Defaults and argument specifications contain exactly the nine variables in
|
- Syntax checking, production-profile ansible-lint, complete integration
|
||||||
the Fixed Public Interface.
|
testing, native minimal and representative configuration validation, and
|
||||||
- The implementation contains no production CLI validation, fingerprints,
|
clean repeated runs pass.
|
||||||
checksums, sidecar build state, manual Git reset or clean commands, or probes
|
- Only `ansible-role-audita` and the workspace control repository change.
|
||||||
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.
|
|
||||||
|
|
||||||
## Dependencies and Follow-up Work
|
## Dependencies and Follow-up Work
|
||||||
|
|
||||||
The managed host requires access to the Audita Git repository, Ubuntu Snap
|
The existing Audita role through commit `3a8c21f` is the implementation
|
||||||
infrastructure, and Go module sources. Runtime processing also requires a
|
baseline. The managed host and test prerequisites are unchanged.
|
||||||
glossary, transcript inputs, LLM endpoints, and secret environment variables;
|
|
||||||
those are consumers' or later suite-level features, not installation
|
|
||||||
dependencies.
|
|
||||||
|
|
||||||
Implementation and focused integration coverage were completed in
|
The configuration amendment was completed in `ansible-role-audita` commits
|
||||||
`ansible-role-audita` commits `47f1852`, `d37f590`, and `3a8c21f`. The D&D
|
`e61f02f` and `847c4c3` and validated by its complete integration suite. The
|
||||||
pipeline role can now select concrete `audita_config` values through the
|
proposed Notarius roadmap should use the same nullable field-specific approach
|
||||||
standalone role's complete-configuration interface.
|
where appropriate.
|
||||||
|
|
||||||
## Potential Future Hardening
|
## Potential Future Hardening
|
||||||
|
|
||||||
- Build into a temporary path before replacing the installed executable.
|
- Validate configuration during production convergence if later operating
|
||||||
- Verify source signatures or release checksums.
|
requirements explicitly select that behavior.
|
||||||
- Detect compiler, build-command, or out-of-band binary changes.
|
- Manage secret environment delivery, diagnostics paths, runtime accounts, or
|
||||||
- Validate configuration during production convergence.
|
services as separate suite-level or application-level features.
|
||||||
- Manage a dedicated runtime account, secret environment, diagnostics path,
|
- Detect source signatures, compiler drift, or out-of-band binary changes if
|
||||||
service, or schedule if later operating requirements select them.
|
the threat model changes.
|
||||||
- Add dedicated Ubuntu release and architecture test matrices.
|
|
||||||
|
|||||||
@@ -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.
|
zero-based, decimal, nested, or nonsequential stage identifiers.
|
||||||
- Before each stage, confirm its preconditions and the working-tree state of
|
- Before each stage, confirm its preconditions and the working-tree state of
|
||||||
its owning repository.
|
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.
|
- Preserve unrelated and pre-existing changes.
|
||||||
- Do not make unresolved product or architecture decisions during execution;
|
- Do not make unresolved product or architecture decisions during execution;
|
||||||
stop and report the decision required.
|
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.
|
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
|
### Preconditions
|
||||||
|
|
||||||
- List facts that must be true before editing begins.
|
- 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
|
Target executor: GPT-5.6-Terra
|
||||||
`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).
|
|
||||||
|
|
||||||
Select and approve the next feature roadmap before replacing this notice with
|
Feature roadmap:
|
||||||
a new staged implementation plan.
|
[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
|
cross-application configuration, D&D campaign deployment, prompt-library
|
||||||
deployment, operator access, the pipeline-wide secret-delivery policy, and
|
deployment, operator access, the pipeline-wide secret-delivery policy, and
|
||||||
end-to-end validation.
|
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
|
- The pipeline role uses the Git-hosted standalone application roles as
|
||||||
dependencies. This is an intentional choice for the controlled project
|
dependencies. This is an intentional choice for the controlled project
|
||||||
environment despite the additional repository and dependency structure and
|
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
|
that installs both the collection and its standalone role dependencies; a
|
||||||
plain collection installation is not assumed to resolve arbitrary Git role
|
plain collection installation is not assumed to resolve arbitrary Git role
|
||||||
dependencies by itself.
|
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
|
This design keeps repository ownership and change blast radius aligned with
|
||||||
the independently released applications while retaining a single opinionated
|
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
|
### 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.
|
- The `narratio` account owns Narratio's writable runtime directories.
|
||||||
- Application source trees and installed binaries are owned by `root` and are
|
- Application source trees and installed binaries are owned by `root` and are
|
||||||
not writable by operators or the runtime account.
|
not writable by operators or the runtime account.
|
||||||
- Ordinary human users run `narratio run` and other Narratio commands directly.
|
- Ordinary human users run `narratio run` and other Narratio commands directly.
|
||||||
- Those operators receive the required access by membership in the `narratio`
|
- Those operators receive the required access by membership in the `narratio`
|
||||||
group.
|
group.
|
||||||
- Managed configuration should be owned by `root`, readable by the `narratio`
|
- Narratio's configuration directory is owned by `root:narratio` with mode
|
||||||
group where needed, and remain under Ansible control rather than being
|
`0750`, and its pipeline file is owned by `root:narratio` with mode `0640`.
|
||||||
routinely edited by operators on the host.
|
Configuration remains under Ansible control rather than being routinely
|
||||||
- Shared runtime directories must grant the `narratio` group the write access
|
edited by operators on the host.
|
||||||
needed for direct operator invocations.
|
- 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
|
### Execution model
|
||||||
|
|
||||||
@@ -237,15 +288,12 @@ remain to be designed.
|
|||||||
|
|
||||||
The following areas require investigation and decisions before implementation:
|
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
|
- The mechanism used to incorporate the independently developed pipeline role
|
||||||
into collection releases
|
into collection releases
|
||||||
- Configuration contracts and filesystem requirements of Notarius, Audita,
|
|
||||||
Seriatim, and Scriptorium
|
|
||||||
- The prompt-library destination and its integration with Scriptorium
|
- The prompt-library destination and its integration with Scriptorium
|
||||||
|
- The campaign repository's checkout revision and deployment/update policy
|
||||||
- Secret injection and storage
|
- Secret injection and storage
|
||||||
- Operator-group membership variables and directory permission details
|
- Suite-level operator-selection variables
|
||||||
- Upgrade, downgrade, and removal behavior
|
- 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
|
Status: resolved
|
||||||
|
|
||||||
The Audita production task flow implements the approved architecture and the
|
Reviewed implementation commits:
|
||||||
complete integration suite passes. The following residual issues should be
|
|
||||||
corrected before Feature 0002 is accepted.
|
|
||||||
|
|
||||||
## 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
|
- `7feff47 Clean up Narratio review findings`
|
||||||
repository's `LICENSE` file is CC0 1.0 Universal. Published role metadata must
|
|
||||||
identify the license actually granted by the repository.
|
|
||||||
|
|
||||||
### 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
|
## Finding 1: Remove the Retained Placeholder README Sentence
|
||||||
`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
|
|
||||||
|
|
||||||
Severity: low
|
Severity: low
|
||||||
|
|
||||||
`ansible-role-audita/README.md` says that the integration suite mutates only
|
`ansible-role-narratio/README.md` ended with the original placeholder sentence,
|
||||||
the three Audita paths and its private temporary directory. Default
|
“Ansible role to install the Narratio D&D transcript and session report
|
||||||
convergence also enables dependency management, so on a fresh supported host
|
generation suite.” The rewritten README already provided the complete role
|
||||||
the suite may install Git through APT, refresh the APT cache, and install the
|
description, so this was accidental residue from the initial repository.
|
||||||
Go Snap. The statement is therefore incomplete.
|
|
||||||
|
|
||||||
### Required Remediation
|
### Resolution
|
||||||
|
|
||||||
- State that the suite may install or converge Git and the Go Snap in addition
|
The retained placeholder sentence was removed without changing the substantive
|
||||||
to managing the listed Audita paths.
|
role documentation.
|
||||||
- Retain the statement that temporary test-specific files are confined to the
|
|
||||||
private temporary directory.
|
|
||||||
|
|
||||||
### Validation
|
## Finding 2: Make the Composition Test Non-vacuous
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
Severity: low
|
Severity: low
|
||||||
|
|
||||||
`tests/verify.yml` checks binary ownership, mode, and executability, but does
|
`ansible-role-narratio/tests/representative.yml` claimed to exercise
|
||||||
not assert that `/usr/local/bin/audita` is a regular file. Stage 1 explicitly
|
caller-side composition, but both secondary fragments were empty. The verifier
|
||||||
requires baseline verification of binary type and metadata. The production
|
consequently proved only that one original entry survived serialization.
|
||||||
`file` task establishes this invariant, but the focused verification does not
|
|
||||||
provide the planned evidence for it.
|
|
||||||
|
|
||||||
### Required Remediation
|
### Resolution
|
||||||
|
|
||||||
- Add an assertion for `audita_binary_metadata.stat.isreg` to the existing
|
The Scriptorium artifact map now combines two nonempty caller-defined
|
||||||
binary metadata check.
|
fragments, and the verifier checks one entry from each. Publish outputs use one
|
||||||
- Do not add another probe or production task.
|
direct value so the suite retains only one representative composition case.
|
||||||
|
Native validation and the immediate clean repeat remain in place.
|
||||||
|
|
||||||
### Validation
|
## Finding 3: Use Ansible Privilege Escalation Directly in Verifiers
|
||||||
|
|
||||||
- `tests/verify.yml` confirms regular-file type, ownership, mode, and
|
|
||||||
executability from its existing `stat` result.
|
|
||||||
- The integration suite passes.
|
|
||||||
|
|
||||||
## Finding 4: Synchronize Implementation Progress Tracking
|
|
||||||
|
|
||||||
Severity: low
|
Severity: low
|
||||||
|
|
||||||
Both implementation stages are annotated complete in
|
Both configuration verifiers escalated to root and then executed
|
||||||
`docs/roadmap/implementation.md`, at role commits `47f1852` and `d37f590`, but
|
`/usr/bin/sudo -u narratio` inside `ansible.builtin.command`, creating a
|
||||||
the plan remains `ready`, its progress notes still say execution is ready to
|
redundant second privilege transition.
|
||||||
begin, and `docs/status.md` still describes execution as the current activity.
|
|
||||||
The recorded state should show that implementation is complete and remediation
|
|
||||||
review is in progress.
|
|
||||||
|
|
||||||
The two workspace commits that added stage-completion annotations also diverge
|
### Resolution
|
||||||
from the plan's instruction that the out-of-band executor leave workspace
|
|
||||||
planning files unchanged. No implementation code was placed in the wrong
|
|
||||||
repository, so this requires tracking cleanup rather than code movement.
|
|
||||||
|
|
||||||
### Required Remediation
|
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
|
## Final Validation
|
||||||
stale progress note with both completed stage commits and the current
|
|
||||||
remediation state.
|
|
||||||
- Update workspace status so Feature 0002 is `in_progress`, with implementation
|
|
||||||
complete and remediation pending, and make review/remediation the current
|
|
||||||
focus.
|
|
||||||
- Do not mark Feature 0002 `done` until remediation is implemented and
|
|
||||||
reviewed.
|
|
||||||
|
|
||||||
### Validation
|
`bash -n tests/integration`, the complete `tests/integration` suite, and
|
||||||
|
`git diff --check` passed after remediation. Syntax checking and
|
||||||
- The plan's status, stage annotations, and progress notes describe one
|
production-profile lint passed within the integration entry point. Baseline,
|
||||||
consistent state.
|
missing-binary recovery, and representative-configuration scenarios passed
|
||||||
- Workspace status agrees with the implementation and remediation records.
|
their native Narratio checks as the application account, every required
|
||||||
- `git diff --check` passes in the workspace repository.
|
immediate repeat reported `changed=0` and `failed=0`, and cleanup restored the
|
||||||
|
usable baseline deployment. No unresolved Feature 0005 findings remain.
|
||||||
## 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.
|
|
||||||
|
|||||||
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
|
# 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 |
|
| 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-03 | Tracked MVP roadmap | workspace | done | `docs/roadmap/mvp.md` established |
|
||||||
| M0-04 | Aggregate repository status | workspace | done | `scripts/status` created |
|
| 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` |
|
| 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-01 | Remaining MVP design decisions | workspace | done | Feature 0003 roadmap fixes the Notarius configuration interface |
|
||||||
| M1-02 | Standalone application roles | role repositories | in_progress | Select the next standalone application role |
|
| 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 | proposed | Begin after standalone role interfaces stabilize |
|
| 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 |
|
| 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` |
|
| 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
|
## 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
|
category: reference
|
||||||
purpose: Existing deployment repository and pipeline_dnd proof of concept
|
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
|
- name: narratio
|
||||||
path: ../narratio
|
path: ../narratio
|
||||||
remote: https://gitea.maximumdirect.net/eric/narratio.git
|
remote: https://gitea.maximumdirect.net/eric/narratio.git
|
||||||
@@ -80,9 +92,3 @@ repositories:
|
|||||||
remote: https://gitea.maximumdirect.net/eric/scriptorium.git
|
remote: https://gitea.maximumdirect.net/eric/scriptorium.git
|
||||||
category: application
|
category: application
|
||||||
purpose: Scriptorium source and authoritative application contracts
|
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