Plan pipeline operator enrollment

This commit is contained in:
2026-09-18 12:44:26 +00:00
parent eda361fa5d
commit a5bc701f60
4 changed files with 616 additions and 15 deletions

View File

@@ -0,0 +1,240 @@
# Feature 0014: Enroll Existing Pipeline Operators
Status: ready
## Summary
Let consumers name existing human accounts that the D&D pipeline role should
add to its shared runtime group. The interface is empty by default, manages
membership additively, and leaves account creation and removal outside the
role.
## Problem or Opportunity
The pipeline's shared filesystem and credential policy already supports
invocation by the dedicated `narratio` service account or by a human member of
the selected runtime group. The role does not yet select human operators or
manage their membership. Consumers must currently repeat a small
`ansible.builtin.user` task beside the role even though group enrollment is a
natural suite-level access choice.
The role must not silently become a general account-management interface.
Human account identity, login policy, credentials, home directories, and
removal remain host or organization concerns. The pipeline needs only a
concise way to enroll explicitly selected existing accounts in the group that
already defines pipeline authorization.
## Governing Policies
- [The Ansible house style](../../ansible.md) requires the smallest direct
desired-state implementation and permits state inspection only when its
result is independently required.
- [The testing house style](../../testing.md) requires a representative
public-interface test of deployed behavior and immediate clean convergence,
without retesting `getent` or `user` module internals.
- [The MVP roadmap](../mvp.md) defines the runtime group as the shared
operator and credential-authorization boundary.
- [Feature 0009](0009-shared-pipeline-filesystem-and-execution.md) establishes
the service-user and human-group-member execution model.
- [Feature 0011](0011-managed-pipeline-credential-delivery.md) establishes
that runtime-group membership authorizes access to the suite's shared
credentials.
- [Feature 0012](0012-collection-assembly.md) makes the standalone pipeline
repository authoritative and requires reviewed changes to enter the
collection through its public Gitea subtree source.
## Scope
- Add `dnd_pipeline_operator_users`, a list of existing account names that
defaults to an empty list.
- Declare the variable as a list of strings in the pipeline role's argument
specification.
- Require every selected account to exist before changing any selected
account's group membership.
- Add each selected account to `dnd_pipeline_runtime_group` with additive
supplementary-group semantics.
- Preserve the existing account, its primary group, and all other
supplementary groups.
- Leave omitted accounts and memberships unmanaged.
- Document the existing-account contract, additive behavior, authorization
consequence, and need to begin a new login session before newly granted
supplementary membership is visible to a long-lived user session.
- Adapt the existing pipeline integration fixture to exercise enrollment
through the new public variable and retain its representative configuration,
secret-access, shared-cache, and clean-repeat behavior.
- Import the reviewed, pushed pipeline commit into the collection through the
established squashed subtree workflow and validate the assembled artifact.
## Non-goals
- Creating, deleting, locking, or otherwise managing human accounts.
- Managing UIDs, primary groups, passwords, SSH keys, shells, home
directories, sudo access, or login policy.
- Removing a user from the runtime group when the user is omitted from the
list or removed from a later inventory value.
- Managing external identity-provider or directory-service membership.
- Adding per-user access controls, separate credential sets, or a second
operator group.
- Changing the `narratio` service account, runtime group, filesystem modes,
ACL policy, credential policy, or application configuration.
- Adding handlers, sidecar state, membership snapshots, post-change
verification, or a custom account-management abstraction.
- Publishing a new pipeline-role or collection release as part of this
implementation.
## Target End State
The pipeline role exposes this optional interface:
```yaml
dnd_pipeline_operator_users:
- eric
- alice
```
The default is `[]`, so existing consumers retain their current behavior. If
the list is nonempty, every named account must already exist on the managed
host. The role fails before its enrollment task when any selected account is
absent; it does not create a partially specified account as a side effect.
Each existing selected account is an additive member of
`dnd_pipeline_runtime_group`. Existing primary and supplementary memberships
remain intact. Membership in that group grants the pipeline access already
defined by Features 0009 and 0011, including shared writable runtime roots and
group-readable suite credentials. Existing login sessions may need to be
restarted before the operating system exposes newly granted supplementary
membership.
Removing a name from `dnd_pipeline_operator_users` does not revoke membership.
Account and access removal require an explicit lifecycle policy and remain
separate work.
The collection's `rakestraw.dnd.pipeline` role contains the same reviewed
interface through a squashed import from the authoritative public pipeline
repository. The published `v0.1.0` release remains unchanged until a later
release feature selects and validates a new version.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the public variable, existing-account
prerequisite, additive enrollment, operator documentation, and detailed
behavioral integration coverage.
- `ansible-collection-dnd` owns the faithful subtree import and its existing
assembled-artifact validation boundary. It does not independently
reimplement or duplicate the pipeline behavior test.
- `ansible-workspace-dnd` owns this roadmap, the settled MVP decision, active
implementation plan, status, and review record.
- The standalone application roles, application sources, asset repositories,
and `rakestraw-ansible` remain unchanged.
## Constraints and Settled Decisions
- The public interface is a simple list of usernames, not a mapping of account
definitions. A richer structure would imply ownership of account creation
and login policy that this feature expressly excludes.
- All selected accounts must exist before enrollment begins. A single
`ansible.builtin.getent` loop over the `passwd` database is justified because
`ansible.builtin.user` with `state: present` would otherwise create a missing
account. No registered fact, separate assertion, or post-enrollment query is
required.
- The enrollment task uses `ansible.builtin.user` with the selected runtime
group and `append: true`. The module owns membership convergence; the role
does not inspect or reconstruct current group lists.
- The enrollment task uses `become: true`. The account-existence lookup does
not require elevation.
- The runtime group continues to be created by the existing Narratio role
dependency before the pipeline role's ordinary tasks execute.
- Empty input naturally skips both loops. No separate conditional, fact, or
branching task is needed.
- Omission is unmanaged, not absent. The feature adds access but does not
define revocation or exact-list reconciliation.
- No username grammar stricter than the managed host's account database is
introduced. The `getent` lookup and `user` module retain ownership of their
native input and error handling.
## Simplest Viable Implementation
Add the empty-list default and matching argument-spec entry. Add one
`ansible.builtin.getent` task that loops over the selected names with database
`passwd` and relies on its default missing-key failure, followed by one
privileged `ansible.builtin.user` task that loops over the same names, selects
`dnd_pipeline_runtime_group`, and uses `append: true`.
Replace the README's consumer-owned membership example with the role variable
and its exact ownership boundary. In the existing integration driver, create
the temporary operator without `narratio` membership before the first role
application, pass that account through `dnd_pipeline_operator_users`, and
retain the existing native configuration and shared-access exercises. Do not
add a missing-user test, inspect `/etc/group`, assert module return data, or
create a second operator scenario.
After the authoritative pipeline change is committed, validated, and pushed,
use the documented public Gitea `git subtree pull --squash` workflow to import
that exact commit into `ansible-collection-dnd`. Run the collection's existing
artifact-boundary integration suite without expanding its detailed feature
matrix.
## Rationale and Alternatives
Keeping membership entirely in each consumer play would avoid two role tasks,
but it leaves every deployment to reproduce access policy already owned by the
suite. An empty-by-default list adds the ergonomic path without affecting
consumers that prefer external membership management.
Passing complete account definitions to the pipeline role would permit it to
create users, but it would also require defaults and policy for homes, shells,
authentication, IDs, and account removal. Those concerns are not pipeline
requirements and belong to host identity management.
Calling `ansible.builtin.user` without first checking existence would be more
compact but would create missing accounts with implicit properties. The
`getent` lookup is therefore independently required to enforce the selected
ownership boundary; it is not defensive re-verification of state already
owned by another module.
Exact-list reconciliation would make removal declarative, but omission has
not been selected as revocation and could remove access managed elsewhere.
Additive enrollment is the smaller and safer contract until lifecycle policy
is designed explicitly.
## Acceptance Criteria
- `dnd_pipeline_operator_users` defaults to an empty list and is declared as a
list of strings in the public argument specification.
- An empty list introduces no account or membership change.
- Every explicitly selected account must already exist, and a missing account
causes convergence to fail before the enrollment task can create or modify
any selected account.
- Each selected existing account is added to
`dnd_pipeline_runtime_group` additively without replacing its other groups.
- Omitted accounts and prior memberships remain unmanaged.
- The role uses only one account-existence task and one enrollment task; it
adds no handler, registered fact, assertion layer, command, private state,
or post-change verification.
- The pipeline documentation explains the variable, existing-account
prerequisite, additive non-removal behavior, group authorization boundary,
and login-session caveat.
- The existing temporary-operator integration scenario enrolls its fixture
through the public variable, demonstrates representative pipeline access,
and the immediate identical second role application reports `changed=0`
and `failed=0`.
- Syntax checking, production-profile lint, the complete standalone pipeline
integration suite, and `git diff --check` pass.
- The exact reviewed pipeline commit is pushed to public Gitea before the
collection imports it.
- The collection subtree contains the reviewed pipeline change through the
documented remote-only squashed import, and the existing collection
integration suite passes against the built and installed artifact.
- No application repository, asset repository, release tag, published
artifact, application configuration, filesystem policy, or credential value
changes.
## Dependencies and Follow-up Work
Features 0009, 0011, 0012, and 0013 are prerequisites. The completed Feature
0013 workspace and collection closeout commits should be pushed before the
implementation sprint begins so local and remote baselines agree.
Upgrade, downgrade, account revocation, exact-membership reconciliation,
application removal, and publication of a release containing this feature
remain separate future work.

View File

@@ -1,8 +1,360 @@
# Implementation Plan
# Implementation Plan 0014: Enroll Existing Pipeline Operators
Status: pending
Status: ready
Feature 0013 is complete. There is no active implementation plan.
Target executor: GPT-5.6-Terra
Select the next unit of work and agree on its numbered feature roadmap before
replacing this notice with a staged implementation plan.
Feature roadmap:
`docs/roadmap/features/0014-existing-pipeline-operator-enrollment.md`
Active plan location: `docs/roadmap/implementation.md`
## Objective
Add one empty-by-default pipeline interface that enrolls explicitly selected
existing human accounts in the suite's runtime group. Implement the behavior
with one account-existence lookup and one additive membership task, adapt the
existing operator integration scenario, and import the reviewed result into
the collection from public Gitea.
The Feature 0014 roadmap remains authoritative for scope, rationale, target
state, and acceptance criteria. This plan does not authorize human-account
creation or removal, exact-list reconciliation, filesystem-policy changes, or
a new release.
## Execution Rules
- Execute stages in numeric order.
- Before each stage, confirm its preconditions and the working-tree state of
its owning repository.
- Before each stage, reread 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. Stop and report unexpected
worktree changes or branch divergence rather than overwriting them.
- Do not make unresolved product or architecture decisions during execution;
stop and report the decision required.
- Keep the production behavior to the roadmap's exact direct task flow: one
`ansible.builtin.getent` loop followed by one `ansible.builtin.user` loop.
- Do not add an assertion, registered fact, handler, command, shell operation,
explicit empty-list condition, membership comparison, post-change query,
sidecar state, or account abstraction.
- Trust `getent` to fail for a missing key and `user` to converge additive
membership. Do not reproduce either module's checks.
- Test the public behavior by adapting the existing temporary-operator
scenario. Do not add a missing-user test, inspect `/etc/passwd` or
`/etc/group`, assert task results, or duplicate the detailed test in the
collection.
- Run each stage's validation before committing it. Do not proceed after a
validation failure.
- Commit each completed stage with the stated plain-English intent. Push the
authoritative pipeline commit before importing it into the collection.
- Use only the public Gitea pipeline URL for the subtree update; do not import
from the local sibling repository.
## Starting State and Preconditions
- Features 0009, 0011, 0012, and 0013 are complete.
- This roadmap and implementation plan have been reviewed and committed in the
workspace repository before execution begins.
- The completed Feature 0013 closeout commits `eda361f` in the workspace and
`5e695f3` in the collection are pushed to their respective `origin/main`
branches before implementation begins. Preserve the Git-generated subtree
squash commit that accompanies `5e695f3`.
- `ansible-role-dnd-pipeline` starts clean on `main` at `78afffe`, equal to
`origin/main`.
- `ansible-collection-dnd` starts clean on `main` at `5e695f3`, equal to
`origin/main` after the prerequisite push.
- The workspace `.venv` supplies the tested `ansible-playbook`,
`ansible-galaxy`, and `ansible-lint` commands used by the repository test
drivers.
- The local host remains the approved Ubuntu 26.04 proxy, and passwordless
test-time sudo is available for the existing integration fixtures.
- Git credentials can push the pipeline and collection commits to their public
Gitea origins.
## Repository Scope
- `ansible-role-dnd-pipeline` owns the variable, argument specification,
account lookup, additive enrollment task, README, and detailed integration
behavior.
- `ansible-collection-dnd` receives the reviewed pipeline commit only through
its established squashed subtree and validates the assembled artifact.
- `ansible-workspace-dnd` records implementation progress and the review
handoff after the two implementation repositories are complete.
- All standalone application-role repositories, application source
repositories, asset repositories, and `rakestraw-ansible` are out of scope
and must remain unchanged.
## Stage 1: Implement Existing-Operator Enrollment
### Objective
Give the standalone pipeline role its minimal public interface for enrolling
existing human accounts and prove the behavior through the existing operator
integration scenario.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/planning.md`
- `docs/roadmap/features/0014-existing-pipeline-operator-enrollment.md`
### Preconditions
- The workspace planning commit is present.
- `ansible-role-dnd-pipeline` is clean at `78afffe` on `main`, is not behind
or diverged from `origin/main`, and contains no unrelated changes.
- Its Narratio dependency still creates the selected runtime group before the
pipeline role's ordinary tasks execute.
- The existing integration driver still contains the temporary operator and
representative group-access scenario described by the roadmap.
### Owning Repository
`ansible-role-dnd-pipeline`
### Required Changes
1. Add `dnd_pipeline_operator_users: []` beside the existing runtime identity
defaults in `defaults/main.yml`.
2. Add the matching `meta/argument_specs.yml` entry with `type: list`,
`elements: str`, and the same required/default-backed convention used by
the role's other public variables.
3. Add one unprivileged `ansible.builtin.getent` task near the beginning of
`tasks/main.yml`. Loop directly over `dnd_pipeline_operator_users`, use the
`passwd` database and each username as `key`, and rely on the module's
default missing-key failure. Do not register its result or add a separate
assertion.
4. Immediately follow it with one `become: true` `ansible.builtin.user` task
over the same list. Set `name` to the selected account,
`groups` to `dnd_pipeline_runtime_group`, `append: true`, and
`state: present`. Do not set or manage any other account property.
5. Revise the README variable reference and shared-execution section. Replace
the consumer-owned membership example and deferred wording with the new
interface, existing-account prerequisite, additive non-removal behavior,
authorization consequence, and new-login-session caveat.
6. Adapt `tests/integration` rather than adding another scenario. Create its
temporary operator before the initial role application without membership
in the runtime group, pass that username through
`dnd_pipeline_operator_users` for the baseline and repeated applications,
and retain the existing native configuration, secret-boundary, and shared
cache exercises under that identity. Reorder cleanup as necessary so any
final baseline convergence occurs while the selected fixture account still
exists, then remove the fixture account.
7. Retain the existing clean-repeat assertion. Do not add a negative
missing-user case or assertions about module internals, task traces, the
current default value, or raw account database entries.
8. Run the complete existing repository validation, commit the result, push
`main` to the public pipeline origin, and record the full pushed commit for
Stage 2.
### Validation
Run from the workspace root:
```text
(cd ansible-role-dnd-pipeline && tests/integration && git diff --check)
```
Expected result: syntax and production-profile lint pass; the temporary
existing account is enrolled through the public role variable and completes
the existing representative operator-access scenario; native application
checks pass; the immediate identical role application reports `changed=0`
and `failed=0`; and no credential value appears in test output.
### Completion Criteria
- The public interface, argument specification, two direct tasks, and README
implement exactly the roadmap contract.
- The existing operator scenario uses the role interface rather than fixture
group enrollment.
- The full standalone integration suite and `git diff --check` pass.
- The role repository is clean after a plain-English commit.
- The exact commit is present on public `origin/main` and its full hash is
available for the collection import.
### Commit
Commit intent: `Add optional pipeline operator enrollment`
## Stage 2: Import the Reviewed Pipeline Change
### Objective
Expose the reviewed operator interface through `rakestraw.dnd.pipeline` while
preserving the authoritative-standalone-repository and collection-artifact
boundaries.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/planning.md`
- `docs/roadmap/features/0014-existing-pipeline-operator-enrollment.md`
- `ansible-collection-dnd/README.md`
### Preconditions
- Stage 1 is complete and its exact commit is publicly reachable from
`https://gitea.maximumdirect.net/eric/ansible-role-dnd-pipeline.git`.
- `ansible-collection-dnd` is clean at `5e695f3` on `main`, is not behind or
diverged from `origin/main`, and contains no unrelated changes.
- The collection's current `roles/pipeline` subtree still corresponds to the
authoritative pipeline history through `78afffe`.
### Owning Repository
`ansible-collection-dnd`
### Required Changes
1. Set a shell variable to the full pushed Stage 1 commit hash and run the
documented remote-only update from the collection repository:
```text
pipeline_revision=<FULL_PUSHED_STAGE_1_COMMIT>
git subtree pull --prefix=roles/pipeline \
https://gitea.maximumdirect.net/eric/ansible-role-dnd-pipeline.git \
"$pipeline_revision" --squash -m "Import pipeline operator enrollment"
```
2. Do not edit role behavior directly beneath `roles/pipeline`. The subtree
import should carry the new default, argument specification, tasks, README,
and standalone tests faithfully.
3. Do not change `galaxy.yml`, dependency manifests, collection-level tests,
or release documentation. No dependency or published version changes in
this feature, and the detailed behavior remains covered by Stage 1.
4. Run the existing collection integration suite against the built and
installed artifact. Commit no additional files after the subtree command
unless validation exposes a genuine collection-boundary issue within this
feature's scope.
5. Push the resulting collection history to `origin/main` and record the
resulting merge commit and Git-generated squashed subtree commit.
### Validation
Run from the workspace root:
```text
(cd ansible-collection-dnd && tests/integration && git diff --check)
```
Expected result: the collection builds; the archive contains the updated
pipeline role while retaining its development-file exclusions; isolated
dependency and artifact installation succeeds; the FQCN resolves; native
representative application checks pass; and the immediate repeat reports
`changed=0` and `failed=0`.
### Completion Criteria
- Git history records a squashed subtree import from the exact public Stage 1
commit with the stated plain-English merge message.
- No pipeline behavior was authored directly in the collection.
- The existing collection suite and `git diff --check` pass without an
unnecessary duplicate operator test.
- The collection is clean and its new history is present on `origin/main`.
### Commit
Commit intent: `Import pipeline operator enrollment`
The subtree command creates the stage's merge commit and its generated squash
commit; do not add an empty or redundant manual commit.
## Stage 3: Record the Implementation Handoff
### Objective
Record the completed implementation evidence without marking Feature 0014
done before independent review.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/planning.md`
- `docs/roadmap/features/0014-existing-pipeline-operator-enrollment.md`
### Preconditions
- Stages 1 and 2 are complete, committed, pushed, and validated.
- Their full commit hashes and validation results are available.
- The workspace repository is clean apart from the expected progress-record
edits for this stage and is not behind or diverged from `origin/main`.
### Owning Repository
`ansible-workspace-dnd`
### Required Changes
1. Change Feature 0014's roadmap status and status-table state to
`in_progress`, indicating implementation is complete but independent review
remains outstanding.
2. Update the workspace current focus and Feature 0014 evidence with the exact
pipeline and collection commit hashes and the validation completed.
3. Replace this plan's Progress Notes with a concise record of the three stage
states and their commits. Do not copy command logs into the repository.
4. Do not mark the feature `done`, remove the active plan, or create
`docs/roadmap/remediation.md`; those are review and closeout decisions.
5. Commit the workspace handoff record with the stated plain-English message.
### Validation
Run from the workspace root:
```text
./scripts/status
git diff --check
```
Expected result: every repository is clean; the pipeline and collection are
not ahead of or behind their origins; only the workspace handoff commit may be
ahead of `origin/main`; and the dashboard points to the exact implementation
evidence while retaining independent review as the next step.
### Completion Criteria
- Workspace status accurately identifies Feature 0014 as implemented and
awaiting review.
- The roadmap remains the durable target-state record and is not polluted with
execution logs.
- The active plan records concise implementation evidence and contains no
false completion claim.
- The workspace repository is clean after the handoff commit.
### Commit
Commit intent: `Record pipeline operator enrollment implementation`
## Final Validation and Handoff
- Confirm Stage 1's complete standalone integration result and Stage 2's
complete collection integration result.
- Run `./scripts/status` and confirm every repository is clean, with no
unexpected branch divergence or untracked artifact.
- Report the full pipeline, collection merge, collection subtree-squash, and
workspace handoff commit hashes.
- Summarize any deviation from this plan, unresolved finding, or added
implementation complexity and identify the acceptance criterion that
required it.
- Do not mark Feature 0014 `done`; implementation results require independent
review first.
## Progress Notes
- Planning complete; implementation has not started.

View File

@@ -16,9 +16,9 @@ The `rakestraw.dnd` collection exposes that role as `rakestraw.dnd.pipeline`.
The suite-level role installs and configures the complete D&D transcript
processing pipeline on a single supported host. Operators or unattended
automation invoke Narratio commands either under the dedicated `narratio`
runtime identity or under a human account that belongs to the `narratio`
group, processing D&D session recordings into transcripts and related
artifacts.
runtime identity or under an explicitly selected existing human account that
belongs to the `narratio` group, processing D&D session recordings into
transcripts and related artifacts.
## Locked Decisions
@@ -253,9 +253,18 @@ application-role releases in one source repository.
- Application source trees and installed binaries are owned by `root` and are
not writable by operators or the runtime account.
- The supported operational model runs `narratio run` and other processing
commands either as the dedicated `narratio` account or as a human account
that is already a member of the `narratio` group. The suite does not yet
select those human accounts or manage their membership.
commands either as the dedicated `narratio` account or as an existing human
account selected through the pipeline role's
`dnd_pipeline_operator_users` list. The list defaults to empty.
- Every selected human account must exist before pipeline convergence. The
role adds selected accounts to the runtime group with additive supplementary
membership and does not create accounts, replace other group memberships,
or manage omitted accounts.
- Removing a name from `dnd_pipeline_operator_users` does not revoke existing
membership. Account and access removal remain outside the MVP until an
explicit lifecycle policy is selected.
- Newly granted supplementary membership may require the operator to begin a
new login session before it becomes visible to that session.
- Application configuration directories and files are owned by
`narratio:narratio`, use modes `0755` and `0644`, respectively, and are
world-readable. Configuration remains under Ansible control rather than
@@ -416,7 +425,6 @@ managed host. The prompt-library checkout retains its upstream `prompts/` and
## Design Work Still Open
The following areas require investigation and decisions before implementation:
The following area requires investigation and decisions before implementation:
- Optional suite-level operator-selection and group-membership management
- Upgrade, downgrade, and removal behavior

View File

@@ -1,10 +1,10 @@
# Workspace Status
Last updated: 2026-09-17
Last updated: 2026-09-18
Current milestone: First coordinated suite release complete
Current focus: Select the next unit of work.
Current focus: Implement Feature 0014.
| ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- |
@@ -30,6 +30,7 @@ Current focus: Select the next unit of work.
| F0011 | Deliver pipeline credentials and Notarius reuse | ansible-role-narratio and ansible-role-dnd-pipeline | done | Implemented and independently reviewed through remediation commit `de1b191` |
| F0012 | Assemble the D&D collection | ansible-collection-dnd and ansible-role-dnd-pipeline | done | Pipeline `600eb21` assembled and validated through collection remediation commit `da67b34` |
| F0013 | Publish the first coordinated suite release | all Ansible repositories and workspace | done | Public [`rakestraw.dnd` 0.1.0 release](https://gitea.maximumdirect.net/eric/ansible-collection-dnd/releases/tag/v0.1.0); documentation remediation completed in pipeline `78afffe` and collection `5e695f3` |
| F0014 | Enroll existing pipeline operators | ansible-role-dnd-pipeline, ansible-collection-dnd, and workspace | ready | Execute `docs/roadmap/implementation.md` in stage order |
| 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 |