Complete the shared pipeline filesystem feature

This commit is contained in:
2026-09-15 15:02:05 +00:00
parent 69961180a2
commit f91871ba0f
4 changed files with 72 additions and 1016 deletions

View File

@@ -1,6 +1,6 @@
# Feature 0009: Shared Pipeline Filesystem and Execution
Status: in_progress
Status: done
## Summary

View File

@@ -1,876 +1,13 @@
# Implementation Plan 0009: Shared Pipeline Filesystem and Execution
# Implementation Plan
Status: ready
Status: pending
Target executor: GPT-5.6-Terra
No implementation plan is currently active. Feature 0009 was implemented,
independently reviewed, and completed through pipeline-role remediation commit
`b15fe8d`. Its durable scope, decisions, and acceptance criteria remain in
[Feature 0009](features/0009-shared-pipeline-filesystem-and-execution.md), and
the completed review record remains in [the remediation
document](remediation.md).
Feature roadmap:
`docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
Active plan location: `docs/roadmap/implementation.md`
## Objective
Give each configuration-bearing standalone role a small, generic ownership
and mode interface, then have the D&D pipeline role select the suite's
`narratio:narratio` and world-readable configuration policy through those
interfaces. Establish setgid and default-ACL behavior on the three existing
Narratio writable roots so the service account and an existing human member of
the shared group can safely use the same state.
The feature roadmap remains authoritative for scope, rationale, target end
state, and acceptance criteria. Decision 0002 remains authoritative for the
shared-readable filesystem boundary.
## 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 if an owning repository is
unexpectedly dirty at a stage boundary.
- Keep standalone roles independently useful. They expose generic owner,
group, directory-mode, and file-mode controls; only the pipeline role selects
`narratio:narratio`, `0755`, and `0644` as D&D suite policy.
- Change only the existing directory and template operations that own
configuration. Do not add corrective permission passes, preliminary
`stat` calls, handlers, validation tasks, checksums, manifests, or
role-private state.
- Trust `ansible.builtin.file`, `ansible.builtin.template`,
`ansible.builtin.apt`, and `ansible.posix.acl` to converge their documented
state. Apply `become: true` only to tasks that require it.
- Keep source checkouts, installed binaries, campaign assets, and prompt
assets outside the new configuration ownership interface.
- Do not create a `secrets/` directory, deliver credentials, select human
operators, alter an existing human account's group membership in production,
or recursively rewrite existing runtime descendants.
- Use `ansible.posix` version `2.2.0`, the current stable release selected for
this plan. Do not substitute another collection or version during execution.
- Test the public operating contract through native application use and actual
cross-identity read/write behavior. Do not assert task order, module results,
exact default values, or filesystem metadata merely to restate module
arguments.
- Run every stage's validation before committing it. Commit each completed
stage when it leaves the owning repository valid, using the plain-English
commit intent specified by that stage.
- Do not begin a dependent stage after an earlier stage fails validation.
- Do not push during implementation. Before Stage 5, the commits produced by
Stages 1 through 4 must nevertheless be reachable from their canonical Git
origins so the pipeline's isolated dependency installation can consume exact
immutable revisions. If they are not reachable, stop after Stage 4 and
report the four hashes for publication rather than weakening the dependency
test or using branch references.
## Starting State and Preconditions
- The workspace control repository contains the committed Feature 0009
roadmap, Decision 0002, and settled MVP filesystem policy at `a7d7189` or a
reviewed descendant.
- Features 0001 through 0008 and the standalone-role test-suite simplification
are complete.
- The following implementation repositories are clean on `main` at these
reviewed starting commits:
| Repository | Starting commit |
| --- | --- |
| `ansible-role-audita` | `d2d0b9d00b3b491ce7613ccfc8f686f3d1fa0896` |
| `ansible-role-notarius` | `cfecf37261f2595d45113235c591ee102d6f181f` |
| `ansible-role-scriptorium` | `8f47aa802a5e0c9dae9c0f43a1c70b3512b2c8b2` |
| `ansible-role-narratio` | `7feff4728a5968b6b1dd87e83add9fa1a9066b18` |
| `ansible-role-dnd-pipeline` | `3e253d714d0e242f2bcb25e1552d3f8511004d85` |
- The four standalone-role starting commits match `origin/main`. The pipeline
starting commit is local and may be ahead of `origin/main`; this is expected
and must not be reset or replaced.
- The workspace `.venv` provides Ansible Core 2.21.3 and ansible-lint 26.8.0.
- The integration host is an accepted Ubuntu 26.04 proxy, supports task-level
privilege escalation, and provides ordinary POSIX ACL support.
- `ansible.posix` 2.2.0 supports Ansible Core 2.16 or newer and supplies the
`ansible.posix.acl` module used by this feature.
- Notarius remains at the Feature 0008-compatible release during this feature.
Its v0.7.0 upgrade, ConfigKit import interface, D&D pipeline, and cache root
belong to Feature 0010.
## Repository Scope
Repositories that change:
- `ansible-role-audita`: generic Audita configuration ownership and mode
interface, argument specification, tasks, and consumer documentation.
- `ansible-role-notarius`: generic Notarius configuration ownership and mode
interface, argument specification, tasks, and consumer documentation.
- `ansible-role-scriptorium`: generic Scriptorium configuration ownership and
mode interface, argument specification, tasks, and consumer documentation.
- `ansible-role-narratio`: generic Narratio configuration ownership and mode
interface, argument specification, tasks, and consumer documentation.
- `ansible-role-dnd-pipeline`: dependency order and pins, suite identity and
configuration policy, ACL dependency and convergence, focused integration
coverage, and consumer documentation.
Repositories that may be inspected but must remain unchanged:
- `ansible-role-seriatim`, which owns no application configuration file.
- `ansible-collection-dnd`, whose assembly remains later work.
- `../{audita,notarius,scriptorium,narratio,seriatim}`, which remain the
read-only application authorities.
- `assets/campaigns`, `assets/narratio-prompts`, and `assets/configs`.
- `rakestraw-ansible` and every other repository in `workspace.yml`.
- The workspace control repository during implementation stages. It is updated
only before or after the sprint for planning and progress management.
## Stage 1: Expose Audita Configuration Ownership
### Objective
Make Audita's managed configuration ownership and modes configurable while
preserving its current standalone installation as the default.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- `ansible-role-audita/defaults/main.yml`
- `ansible-role-audita/meta/argument_specs.yml`
- `ansible-role-audita/tasks/main.yml`
- `ansible-role-audita/tests/integration`
- `ansible-role-audita/README.md`
### Preconditions
- `ansible-role-audita` is clean at the stated starting commit.
- Its existing integration suite passes before modification.
### Owning Repository
`ansible-role-audita`
### Required Changes
1. Add these required, defaulted public variables:
`audita_config_owner: root`, `audita_config_group: root`,
`audita_config_directory_mode: "0755"`, and
`audita_config_file_mode: "0644"`.
2. Add matching string entries to `meta/argument_specs.yml`, with descriptions
that distinguish the configuration directory mode from the managed file
mode.
3. Keep source and binary parent directories `root:root` mode `0755`. Manage
`audita_config_path | dirname` directly with the four configuration inputs,
either by giving it a distinct declarative file task or by using an equally
clear existing loop shape.
4. Replace the template task's hard-coded owner, group, and mode with the new
variables. Do not add a follow-up file task, state inspection, or other task
flow.
5. Document all four variables and their standalone defaults in the README.
Explain that composing roles may override them; do not introduce D&D policy
into this role.
6. Keep the existing focused integration suite and clean-repeat contract. Do
not add metadata assertions or a test whose only purpose is to prove that
`file` or `template` honored its arguments.
### Validation
Run from `ansible-role-audita`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: syntax and lint pass, Audita natively validates its managed
configuration, every existing representative behavior remains valid, the
immediate repeat reports `changed=0` and `failed=0`, and only intended Audita
role files are modified.
### Completion Criteria
- The four public inputs, argument specification, directory operation,
template operation, and README agree.
- The default standalone result remains `root:root`, `0755` for the directory,
and `0644` for the file.
- No new production task exists solely to inspect or repair module-managed
state.
### Commit
Commit intent: `Make Audita configuration ownership configurable`
## Stage 2: Expose Notarius Configuration Ownership
### Objective
Make Notarius's managed configuration ownership and modes configurable while
leaving its application version and configuration schema unchanged for Feature
0010.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- `ansible-role-notarius/defaults/main.yml`
- `ansible-role-notarius/meta/argument_specs.yml`
- `ansible-role-notarius/tasks/main.yml`
- `ansible-role-notarius/tests/integration`
- `ansible-role-notarius/README.md`
### Preconditions
- Stage 1 is committed and validated.
- `ansible-role-notarius` is clean at the stated starting commit.
- Its existing integration suite passes before modification.
### Owning Repository
`ansible-role-notarius`
### Required Changes
1. Add `notarius_config_owner: root`, `notarius_config_group: root`,
`notarius_config_directory_mode: "0755"`, and
`notarius_config_file_mode: "0644"` as required, defaulted public inputs.
2. Add matching string argument-specification entries.
3. Keep source and binary parents under the existing `root:root` mode `0755`
policy. Apply the new inputs directly when managing
`notarius_config_path | dirname`.
4. Use the same inputs directly in the existing configuration template task.
Do not add permission-repair tasks, inspection, handlers, or validation to
production convergence.
5. Document the interface and standalone defaults without mentioning the D&D
cache, ConfigKit imports, Notarius v0.7.0, or any other Feature 0010 work.
6. Retain the existing native and clean-repeat integration behavior without
adding filesystem metadata assertions or tests of trusted modules.
### Validation
Run from `ansible-role-notarius`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: syntax and lint pass, the current Notarius configuration and
explicit version-selection cases remain natively valid, all immediate repeats
remain clean, and only intended Notarius role files are modified.
### Completion Criteria
- The generic four-variable interface is complete and documented.
- Existing version, schema, cache, and pipeline behavior is unchanged.
- Standalone defaults remain `root:root`, `0755`, and `0644`.
- Production convergence contains no redundant permission machinery.
### Commit
Commit intent: `Make Notarius configuration ownership configurable`
## Stage 3: Expose Scriptorium Configuration Ownership
### Objective
Make Scriptorium's managed configuration ownership and modes configurable while
preserving its current generic standalone behavior.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- `ansible-role-scriptorium/defaults/main.yml`
- `ansible-role-scriptorium/meta/argument_specs.yml`
- `ansible-role-scriptorium/tasks/main.yml`
- `ansible-role-scriptorium/tests/integration`
- `ansible-role-scriptorium/README.md`
### Preconditions
- Stages 1 and 2 are committed and validated.
- `ansible-role-scriptorium` is clean at the stated starting commit.
- Its existing integration suite passes before modification.
### Owning Repository
`ansible-role-scriptorium`
### Required Changes
1. Add `scriptorium_config_owner: root`, `scriptorium_config_group: root`,
`scriptorium_config_directory_mode: "0755"`, and
`scriptorium_config_file_mode: "0644"` as required, defaulted public
variables.
2. Add the matching string argument-specification entries.
3. Leave source and binary parent policy unchanged. Apply the new variables
directly to the operation that creates
`scriptorium_config_path | dirname`.
4. Replace the template task's fixed configuration metadata with the new
variables. Do not add a second convergence pass or preliminary inspection.
5. Document the generic interface and standalone defaults. Do not add Narratio
or D&D assumptions to this reusable role.
6. Keep the existing native profile-inspection and clean-repeat suite focused;
do not add file metadata checks.
### Validation
Run from `ansible-role-scriptorium`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: syntax and lint pass, representative native Scriptorium
inspection remains successful, the immediate repeats report `changed=0` and
`failed=0`, and only intended Scriptorium role files are modified.
### Completion Criteria
- Defaults, argument specification, tasks, and README expose one coherent
generic ownership interface.
- Standalone configuration remains `root:root`, directory mode `0755`, and
file mode `0644` by default.
- No new task or test merely re-proves trusted module behavior.
### Commit
Commit intent: `Make Scriptorium configuration ownership configurable`
## Stage 4: Expose Narratio Configuration Ownership
### Objective
Separate Narratio's generic configuration-file policy from its runtime identity
and writable-root policy, preserving the current standalone defaults while
allowing a composing role to make configuration service-owned.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- `ansible-role-narratio/defaults/main.yml`
- `ansible-role-narratio/meta/argument_specs.yml`
- `ansible-role-narratio/tasks/main.yml`
- `ansible-role-narratio/tests/integration`
- `ansible-role-narratio/README.md`
### Preconditions
- Stages 1 through 3 are committed and validated.
- `ansible-role-narratio` is clean at the stated starting commit.
- Its existing integration suite passes before modification.
### Owning Repository
`ansible-role-narratio`
### Required Changes
1. Add `narratio_config_owner: root`,
`narratio_config_group: "{{ narratio_group }}"`,
`narratio_config_directory_mode: "0750"`, and
`narratio_config_file_mode: "0640"` as required, defaulted public inputs.
The group default deliberately follows the role's existing configurable
service group.
2. Add matching string argument-specification entries.
3. Use the four variables directly in the existing configuration-directory
and pipeline-template tasks.
4. Do not change creation of `narratio_user` or `narratio_group`, the three
mutable Narratio roots, the campaign registry root, source checkout, binary,
application fields, or task ordering.
5. Document the new interface and its standalone relationship to
`narratio_group`. Make clear that configuration ownership is independent of
writable runtime-root ownership.
6. Retain the existing native validation, representative configuration, and
immediate clean-repeat behavior. Do not add metadata assertions.
### Validation
Run from `ansible-role-narratio`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: syntax and lint pass, Narratio natively validates baseline and
representative configurations as its service account, all immediate repeats
are clean, and only intended Narratio role files are modified.
### Completion Criteria
- The configuration interface defaults to the prior standalone result:
`root:{{ narratio_group }}`, directory mode `0750`, and file mode `0640`.
- Runtime identity and mutable-root behavior remain unchanged.
- Configuration directory and template tasks are the sole production owners of
their respective metadata.
### Commit
Commit intent: `Make Narratio configuration ownership configurable`
## Stage 5: Apply the Suite Configuration Ownership Policy
### Objective
Make Narratio establish the selected runtime identity first, then use the four
standalone interfaces to converge every application configuration and
pipeline-owned Narratio fragment under the D&D suite policy.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- the four standalone-role commits produced by Stages 1 through 4
- `ansible-role-dnd-pipeline/defaults/main.yml`
- `ansible-role-dnd-pipeline/meta/argument_specs.yml`
- `ansible-role-dnd-pipeline/meta/main.yml`
- `ansible-role-dnd-pipeline/requirements.yml`
- `ansible-role-dnd-pipeline/tasks/main.yml`
- `ansible-role-dnd-pipeline/tests/integration`
### Preconditions
- Stages 1 through 4 are committed, validated, and otherwise clean.
- Each new standalone-role commit is reachable from its canonical origin. Stop
and report the hashes if a fresh Git or Galaxy fetch cannot resolve them.
- `ansible-role-dnd-pipeline` is clean at its stated starting commit or an
expected reviewed descendant.
- The existing pipeline integration suite passes before modification.
### Owning Repository
`ansible-role-dnd-pipeline`
### Required Changes
1. Add the required suite defaults and matching argument-specification entries:
`dnd_pipeline_runtime_user: narratio`,
`dnd_pipeline_runtime_group: narratio`,
`dnd_pipeline_config_directory_mode: "0755"`, and
`dnd_pipeline_config_file_mode: "0644"`.
2. Reorder `meta/main.yml` so `rakestraw.narratio` is the first dependency and
therefore creates the selected service account and group before any other
configuration-bearing role uses them. Preserve the remaining dependency
roles and all existing application wiring.
3. Pass the runtime user and group to `narratio_user` and `narratio_group`.
Pass the runtime user, runtime group, suite directory mode, and suite file
mode to the four new `narratio_config_*` variables.
4. Pass the same four suite values to the corresponding `audita_config_*`,
`notarius_config_*`, and `scriptorium_config_*` variables. Do not apply a
corrective ownership task after a dependency completes.
5. Update `requirements.yml` to pin the Audita, Notarius, Scriptorium, and
Narratio dependencies to the exact commits produced by Stages 1 through 4.
Keep canonical Git URLs and immutable commit hashes; do not use branches or
local-path substitutes.
6. Apply the selected runtime group to the pipeline-managed prompt-library
root. Apply the suite configuration owner, group, directory mode, and file
mode directly to the existing Narratio fragment directory and template
loops. Campaign and prompt Git content remains root-managed and
world-readable.
7. Do not add ACL or package tasks in this stage. Do not change application
versions, native configuration fields, assets, Notarius enablement, or the
Feature 0010 cache path.
### Validation
Run from `ansible-role-dnd-pipeline`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: a fresh isolated role installation resolves the four new
immutable commits; Narratio runs first without missing-identity failures; all
five applications and the assembled Narratio configuration remain natively
usable; the immediate baseline repeat reports `changed=0` and `failed=0`; and
only intended pipeline-role files are modified.
### Completion Criteria
- One suite-level identity and configuration-mode policy is passed through the
four generic role interfaces.
- All pipeline-owned Narratio configuration uses the same policy directly.
- Dependency order and immutable pins refer to the completed standalone stages.
- No follow-up task fights a dependency role's ownership or mode state.
- Existing pipeline behavior remains valid and immediately idempotent.
### Commit
Commit intent: `Apply shared configuration ownership to the D&D pipeline`
## Stage 6: Establish Shared Writable-Root ACLs
### Objective
Apply the settled setgid and inherited-access policy to the three existing
Narratio writable roots using direct package and ACL convergence.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- `ansible-role-narratio/tasks/main.yml`
- `ansible-role-dnd-pipeline/collections/requirements.yml`
- `ansible-role-dnd-pipeline/tasks/main.yml`
- the official `ansible.posix.acl` 2.2.0 module documentation
### Preconditions
- Stage 5 is committed and validated.
- The pipeline role creates the runtime identity and Narratio creates
`/var/lib/narratio`, `/var/spool/narratio`, and `/var/cache/narratio` as the
selected user and group with mode `2775` before pipeline tasks run.
- `ansible.posix` 2.2.0 and Ubuntu's `acl` package remain available.
### Owning Repository
`ansible-role-dnd-pipeline`
### Required Changes
1. Add `ansible.posix` version `2.2.0` to
`collections/requirements.yml`, retaining the existing
`community.general` pin.
2. Add one direct privileged `ansible.builtin.apt` task for package `acl` with
`state: present`, `update_cache: true`, and `cache_valid_time: 3600`.
3. Use the smallest clear `ansible.posix.acl` loop or loops to manage access
and default entries on exactly `/var/lib/narratio`,
`/var/spool/narratio`, and `/var/cache/narratio`. For each root, converge
entries equivalent to `u::rwx`, `g::rwx`, `o::r-x`, and `m::rwx` for both
access and default ACLs.
4. Apply `become: true` to the package and ACL tasks. Keep ACL convergence
non-recursive: manage the roots and inheritance for new descendants, not
pre-existing descendants.
5. Do not add `stat`, `getfacl`, shell commands, handlers, ACL facts, manual
change detection, wrapper umasks, or fallback permission repair to
production tasks. Do not create `/var/cache/notarius` or `secrets/`.
### Validation
Run from `ansible-role-dnd-pipeline`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: the private collection bootstrap installs both pinned
collections; syntax and production-profile lint pass; ACL convergence succeeds
on all three existing roots; all existing native checks pass; and the
immediate repeat reports `changed=0` and `failed=0`.
### Completion Criteria
- The collection and host-package requirements are explicit and pinned where
applicable.
- Each shared root retains mode `2775` from the Narratio role and has the
selected access and default ACL entries.
- Production logic uses only direct package and ACL state management and does
not recursively mutate existing content.
- Existing pipeline validation and clean convergence remain green.
### Commit
Commit intent: `Manage shared pipeline access with ACLs`
## Stage 7: Exercise Cross-Identity Pipeline Access
### Objective
Prove the suite's user-visible read and shared-write contract with one isolated
human-operator fixture while retaining the existing focused integration suite.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- `ansible-role-dnd-pipeline/tests/integration`
- `ansible-role-dnd-pipeline/tests/converge.yml`
- `ansible-role-dnd-pipeline/tasks/main.yml`
### Preconditions
- Stages 1 through 6 are committed and validated.
- The integration driver can create and remove one uniquely named test-only
local account through privilege escalation without touching an existing
human account.
- The service account, selected group, managed configuration, and three shared
roots exist through ordinary baseline convergence.
### Owning Repository
`ansible-role-dnd-pipeline`
### Required Changes
1. Retain the driver's isolated role and collection installation, immutable
asset inputs, native application checks, explicit configurable-behavior
cases, cleanup boundary, and immediate clean repeats.
2. Create one uniquely named test-only operator account after baseline
convergence and add only that account to the selected runtime group. This
is integration fixture setup, not production role behavior. Ensure cleanup
removes only the fixture account and its explicitly named test content on
both success and failure; never modify a real operator account.
3. As the test operator, run one existing native Narratio configuration
validation or inspection command against the same managed configuration and
campaign used by the service account. This proves the supported human
invocation boundary without duplicating every application check.
4. Under one uniquely named child of a shared Narratio root, create ordinary
content as the service account with a restrictive ordinary umask and modify
or read it as the test operator. Then create representative content as the
operator and modify or read it as the service account. Use actual access as
the assertion; do not parse mode bits or `getfacl` output.
5. Use one existing unprivileged account outside the shared group to read a
representative non-secret configuration or test artifact, establishing the
deliberate world-readable boundary. Do not grant that account write access
or add it to the shared group.
6. Keep one immediate identical role repeat after the new policy is active and
require `changed=0` and `failed=0`. Test-created descendants must not cause
recursive role changes.
7. Do not test every root, every application configuration, every ACL entry, or
Ansible's file, user, group, package, template, or ACL implementation. Do
not create credentials or a secrets fixture.
### Validation
Run from `ansible-role-dnd-pipeline`:
```text
tests/integration
git diff --check
git status --short
```
Expected result: all prior checks remain green; the service account and one
existing-group-member fixture use the same Narratio configuration; both
identities exchange representative shared-root content despite a restrictive
ordinary umask; an account outside the group can read but is never granted
write access; cleanup removes only test-owned state; and the immediate role
repeat reports `changed=0` and `failed=0`.
### Completion Criteria
- Tests observe the supported operating contract rather than filesystem
metadata or task implementation.
- The human-user fixture is isolated, uniquely named, and reliably cleaned up.
- One representative root and configuration path provide sufficient coverage;
no exhaustive access matrix is added.
- The complete integration entry point remains the sole supported test command
and is immediately idempotent.
### Commit
Commit intent: `Test shared pipeline access across users`
## Stage 8: Document the Shared Execution Model
### Objective
Document the standalone ownership interfaces and the pipeline's opinionated
service identity, readable configuration, shared writable state, operator
prerequisites, and secret boundary.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
- `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md`
- `docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md`
- the four standalone-role READMEs updated in Stages 1 through 4
- `ansible-role-dnd-pipeline/README.md`
### Preconditions
- Stages 1 through 7 are committed and validated.
- All final variable names, dependency pins, task behavior, and integration
commands are stable and match the feature roadmap.
### Owning Repository
`ansible-role-dnd-pipeline`
### Required Changes
1. Add the four suite variables to the pipeline README and explain that they
are deliberate D&D policy passed to the standalone roles rather than
standalone defaults.
2. Document dependency order: Narratio establishes the runtime user and group
before the remaining configuration-bearing dependencies run.
3. Document `narratio:narratio`, directory mode `0755`, and file mode `0644`
for application configuration, including the pipeline-owned Narratio
fragments. Explain that this ordinary configuration is Ansible-managed and
intentionally world-readable, not operator-edited in place.
4. Document the three shared roots, their `2775` setgid mode, inherited ACL
policy, and supported invocation as either the service account or a human
account already belonging to the runtime group. Use the term **setgid**, not
sticky bit.
5. State clearly that the production role does not select human users or manage
their group membership. Provide a concise consumer-side inventory or
operational example without embedding a particular human username.
6. Explain that configuration, transcripts, caches, generated artifacts,
campaign data, prompts, and logs are treated as non-secret D&D content. API
keys and credentials are deferred to the future restricted `secrets/`
subtree; do not imply that this feature creates it.
7. Update validation documentation to describe the representative native
operator check, actual shared-write exchange, world-readable check, and
immediate clean repeat without promising exhaustive permission testing.
### Validation
Run from `ansible-role-dnd-pipeline`:
```text
tests/integration
git diff --check HEAD
git status --short
```
Expected result: the complete suite remains syntax-clean, lint-clean, natively
valid, cross-identity usable, and immediately idempotent; documentation matches
the implemented interface and paths; and no whitespace errors are reported.
### Completion Criteria
- Consumers can distinguish standalone defaults from suite overrides.
- The service-user and existing-group-member invocation paths, setgid/ACL
behavior, world-readable boundary, and deferred secrets boundary are clear.
- Documentation does not promise group-membership management, recursive
migration, Notarius v0.7.0 integration, or secret delivery.
- All five changed repositories remain valid after the documentation commit.
### Commit
Commit intent: `Document the shared pipeline execution model`
## Final Validation and Handoff
After Stage 8, run each owning repository's complete integration entry point:
```text
cd ansible-role-audita && tests/integration
cd ../ansible-role-notarius && tests/integration
cd ../ansible-role-scriptorium && tests/integration
cd ../ansible-role-narratio && tests/integration
cd ../ansible-role-dnd-pipeline && tests/integration
```
Then, from the workspace root, run:
```text
git diff --check
./scripts/status
```
The final handoff must:
- identify all eight implementation commit hashes and confirm every changed
repository has a clean working tree;
- confirm syntax and production-profile lint pass in all five changed roles;
- confirm every standalone role's native behavior and immediate clean repeat
pass;
- confirm the pipeline installs the exact immutable standalone commits,
applies the configuration and ACL policy, supports representative
cross-identity access, and immediately reports `changed=0` and `failed=0`;
- confirm no application source, asset, collection, Seriatim role, secret,
human operator account, or unrelated repository was modified;
- summarize any deviation, blocker, or deferred work, including whether
dependency publication required a coordination pause;
- report any production complexity beyond the planned public variables,
direct task substitutions, dependency wiring, one package task, and the
minimum clear ACL loop or loops, together with the acceptance criterion that
required it; and
- leave Feature 0009 `ready` or `in_progress` for independent review rather
than marking it `done`.
## Progress Notes
Stages 1 through 4 and the dependency-publication checkpoint are complete.
Resume at Stage 5. Continue recording only concise stage commit hashes and
blockers here; preserve detailed evidence in the stage commits and final
handoff.
- [x] Stage 1 complete — `ansible-role-audita` commit `66ebea9`; full
integration, native validation, and clean repeats passed. No deviations.
- [x] Stage 2 complete — `ansible-role-notarius` commit `e9ae2dc`; full
integration, native validation, version selection, and clean repeats passed.
No deviations.
- [x] Stage 3 complete — `ansible-role-scriptorium` commit `8b4c86e`; full
integration, native profile inspection, and clean repeats passed. No
deviations.
- [x] Stage 4 complete — `ansible-role-narratio` commit `eeb1105`; full
integration, native validation, and clean repeats passed. No deviations.
- [x] Dependency publication checkpoint complete — the four Stage 1–4 commits
are available from their canonical `origin/main` branches at the exact
immutable revisions listed above. Stage 5 may begin.
- [x] Stage 5 complete — `ansible-role-dnd-pipeline` commit `901ae35`; full
isolated integration, immutable dependency installation, native validation,
and clean repeats passed. No deviations.
- [x] Stage 6 complete — `ansible-role-dnd-pipeline` commit `dddc5ee`; full
isolated integration, ACL convergence, native validation, and clean repeats
passed. No deviations.
- [x] Stage 7 complete — `ansible-role-dnd-pipeline` commit `f53da82`; full
isolated integration, cross-identity access, native validation, and clean
repeats passed. No deviations.
- [x] Stage 8 complete — `ansible-role-dnd-pipeline` commit `608d5be`; full
isolated integration, documentation validation, and clean repeats passed.
No deviations.
Select and approve the next unit of work before replacing this notice with a
new staged implementation plan.

View File

@@ -1,6 +1,6 @@
# Feature 0009 Remediation Review
Status: open
Status: resolved
Reviewed implementation commits:
@@ -8,164 +8,83 @@ Reviewed implementation commits:
- `e9ae2dc Make Notarius configuration ownership configurable`
- `8b4c86e Make Scriptorium configuration ownership configurable`
- `eeb1105 Make Narratio configuration ownership configurable`
- `901ae35 Apply shared configuration ownership to the D&D pipeline`
- `dddc5ee Manage shared pipeline access with ACLs`
- `f53da82 Test shared pipeline access across users`
- `608d5be Document the shared pipeline execution model`
## Review Summary
The four completed standalone-role stages are concise, idiomatic, and aligned
with Feature 0009. Each role exposes owner, group, configuration-directory
mode, and configuration-file mode variables; applies them directly through the
ordinary `file` and `template` tasks; preserves its standalone defaults; and
documents the interface. No redundant inspection, corrective convergence,
private state, or unrelated application behavior was introduced. All four
repository-local integration suites passed independently during review.
The production architecture and behavioral coverage implement Feature 0009 as
planned. The four standalone roles expose generic configuration ownership and
mode controls, and the pipeline selects its opinionated service-owned,
world-readable policy through those interfaces. Narratio establishes the
runtime identity first. The pipeline then installs ACL support and directly
converges access and default ACLs on the three existing shared roots. Focused
integration coverage exercises actual cross-identity configuration access and
bidirectional writes under a restrictive umask while preserving immediate clean
convergence.
Feature 0009 as a whole is not implemented. The pipeline repository remains at
pre-feature commit `3e253d7`; Stages 5 through 8 have not been executed. The
publication blocker encountered after Stage 4 has now been cleared: all four
standalone commits are available from their canonical origins. The following
findings therefore describe the remaining target architecture rather than
defects in the completed standalone commits.
No production code or test-suite remediation is required. One small consumer
documentation inconsistency remains.
## Finding 1: The Pipeline Does Not Select the Shared Configuration Policy
## Finding 1: Operator Support Is Documented Inconsistently
Severity: high
Severity: low
`ansible-role-dnd-pipeline/defaults/main.yml` and
`meta/argument_specs.yml` do not define the four suite-level runtime identity
and configuration-mode variables. `meta/main.yml:19-98` still runs Narratio
last and does not pass the new configuration ownership interfaces to Audita,
Notarius, Scriptorium, or Narratio. `requirements.yml:7-22` still pins the four
pre-feature role commits.
`ansible-role-dnd-pipeline/README.md:201-217` first lists "operator access" as
deferred, then correctly states that invocation by an existing member of the
selected runtime group is supported. The likely deferred concern is operator
selection and group-membership management, not operator access itself.
Consequently, applying the current pipeline role retains standalone ownership:
Audita, Notarius, and Scriptorium configuration remains `root:root`, while
Narratio configuration remains `root:narratio` with its standalone restrictive
modes. The target `narratio:narratio`, `0755` directory, and `0644` file suite
policy is not selected. Narratio also does not establish the service identity
before the other configuration-bearing dependencies run.
The adjacent YAML fragment defines an otherwise unexplained
`operator_group_members` variable but shows no consumer task or role that uses
it. As written, copying the example does not manage any membership and may lead
a reader to believe that the pipeline role consumes that variable.
### Required Remediation
- Use the four published, immutable standalone-role commits recorded above;
do not replace their commit pins with branches.
- Execute Stage 5 of `docs/roadmap/implementation.md` in full.
- Add the four suite defaults and argument-spec entries, run Narratio first,
pass the selected identity and modes through every generic role interface,
update the four dependency pins, and apply the same values directly to the
pipeline-owned Narratio fragments.
- Retain direct module convergence without any post-dependency permission
repair.
- Replace "operator access" in the deferred list with the precise deferred
behavior: operator selection and group-membership management.
- Replace the inert variable fragment with a concise, complete consumer-side
example that actually adds a selected account to the runtime group, or omit
the example and state the prerequisite directly.
- Keep human account and membership management outside the production pipeline
role.
## Finding 2: Shared Writable-Root ACL Convergence Is Absent
## Resolution
Severity: high
`ansible-role-dnd-pipeline/collections/requirements.yml:1-4` contains only
`community.general`. `tasks/main.yml:1-65` neither installs Ubuntu's `acl`
package nor uses `ansible.posix.acl`. The three Narratio writable roots still
receive mode `2775` from the standalone role, but the suite does not establish
the access and default ACLs required to preserve group write and world
read/traverse behavior across invocation identities with different umasks.
### Required Remediation
- Execute Stage 6 of the implementation plan in full.
- Pin `ansible.posix` 2.2.0 alongside the existing collection dependency.
- Install `acl` with one ordinary privileged `ansible.builtin.apt` task.
- Apply the selected access and default ACL entries to exactly
`/var/lib/narratio`, `/var/spool/narratio`, and `/var/cache/narratio` with
direct, non-recursive `ansible.posix.acl` convergence.
- Do not add filesystem probes, `getfacl` production commands, recursive
migration, handler flow, or supplemental permission repair.
## Finding 3: The Shared Execution Contract Has No Behavioral Coverage
Severity: medium
`ansible-role-dnd-pipeline/tests/integration:64-133` exercises the established
pipeline only as root and the `narratio` service account. It does not use a
representative existing member of the shared group, exchange writable-state
content between invocation identities, exercise inheritance under a
restrictive ordinary umask, or observe the deliberate world-readable boundary.
The missing tests are important because the group-sharing outcome is suite
behavior authored by this feature, not a request to re-test an individual
Ansible module. The tests should exercise actual access rather than assert
mode values or parse ACL metadata.
### Required Remediation
- Execute Stage 7 of the implementation plan after Findings 1 and 2 are
resolved.
- Use one uniquely named, test-owned operator account as an integration
fixture and clean up only that account and its explicitly named content.
- Validate one representative Narratio operation as that group member and one
bidirectional content exchange with the service account.
- Observe one representative world-readable configuration or artifact as an
account outside the group.
- Preserve immediate clean repeated convergence and avoid an exhaustive
identity, path, mode, or ACL matrix.
## Finding 4: Pipeline Consumer Documentation Is Stale
Severity: medium
`ansible-role-dnd-pipeline/README.md:185` still lists operator access among
deferred concerns. It does not document the new suite variables,
Narratio-first dependency order, service-owned and world-readable
configuration, shared setgid roots, inherited ACL behavior,
existing-group-member invocation, or the restricted future `secrets/`
boundary.
### Required Remediation
- Execute Stage 8 of the implementation plan after the production behavior and
tests are complete.
- Clearly distinguish generic standalone defaults from the pipeline's
opinionated overrides.
- Document setgid terminology, the three shared roots, supported invocation
identities, the fact that production does not manage human membership, and
the deliberate non-secret boundary.
- Do not promise the deferred secrets implementation, recursive migration, or
Feature 0010 Notarius behavior.
Resolved in pipeline-role commit `b15fe8d`. The deferred-work summary now
names operator selection and group-membership management rather than operator
access. The shared-filesystem section retains existing-group-member invocation
as supported behavior and provides a complete consumer-owned
`ansible.builtin.user` example that adds a selected account to the runtime
group. No production role behavior changed.
## Required Validation
After remediation, run the complete integration entry point in each changed
role:
```text
cd ansible-role-audita && tests/integration
cd ../ansible-role-notarius && tests/integration
cd ../ansible-role-scriptorium && tests/integration
cd ../ansible-role-narratio && tests/integration
cd ../ansible-role-dnd-pipeline && tests/integration
```
Then run from the workspace root:
After the documentation correction, run:
```text
cd ansible-role-dnd-pipeline && tests/integration
git diff --check
./scripts/status
```
The expected result is that all five role suites pass syntax and lint checks,
native application checks succeed, the shared cross-identity contract is
observed, every immediate repeat reports `changed=0` and `failed=0`, all eight
implementation-stage commits are identified, and every repository is clean.
The expected result remains successful native configuration checks,
representative cross-identity access, and immediate repeats with `changed=0`
and `failed=0`.
## Review Validation Evidence
During this review, the complete `tests/integration` entry points passed in
`ansible-role-audita`, `ansible-role-notarius`,
`ansible-role-scriptorium`, and `ansible-role-narratio`. Each suite installed
its pinned collection dependencies, passed syntax checking and
production-profile lint, exercised its native application behavior, and
reported clean immediate repeats. `git diff --check` passed and all
implementation repositories remained clean after testing.
The independent review inspected the complete diffs for all eight stage
commits and confirmed that every dependency pin resolves to the intended
standalone-role commit. `git diff --check` passed across all five changed role
repositories. The complete pipeline `tests/integration` entry point passed its
isolated dependency installation, syntax check, production-profile lint,
native application checks, cross-identity access exercise, configurable
profile and version cases, and immediate clean repeats. All repositories were
clean before this review document was revised.
The pipeline suite was not presented as Feature 0009 validation evidence
because the pipeline repository contains no Feature 0009 implementation
commits. Its current test suite exercises the prior Feature 0008 architecture.
After review, each standalone commit was pushed to its canonical `origin/main`
branch and the local and remote-tracking revisions were confirmed identical.
After remediation, the complete pipeline integration entry point and
`git diff --check` passed again. The test fixture was removed and the baseline
Seriatim version and pipeline configuration were restored during cleanup.

View File

@@ -1,10 +1,10 @@
# Workspace Status
Last updated: 2026-09-14
Last updated: 2026-09-15
Current milestone: M1-03 suite-level pipeline role
Current focus: Independently review the completed Feature 0009 implementation.
Current focus: Select the next unit of work.
| ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- |
@@ -15,7 +15,7 @@ Current focus: Independently review the completed Feature 0009 implementation.
| 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 | done | Feature 0003 roadmap fixes the Notarius configuration interface |
| M1-02 | Standalone application roles | role repositories | done | All five standalone roles implemented and independently reviewed |
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | in_progress | Feature 0009 implementation and final validation are complete; await independent review |
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | in_progress | Feature 0009 is complete; select the next suite-policy feature |
| M1-04 | Collection assembly | ansible-collection-dnd | proposed | Select and implement the pipeline-role incorporation mechanism |
| F0001 | Install Seriatim from pinned source | ansible-role-seriatim | done | Implementation, integration coverage, and final remediation completed through `fb8dc41` |
| F0002 | Install and configure Audita | ansible-role-audita | done | Field-specific configuration completed in `e61f02f` and `847c4c3`; full suite passed |
@@ -25,8 +25,8 @@ Current focus: Independently review the completed Feature 0009 implementation.
| F0006 | Establish pipeline-role composition | ansible-role-dnd-pipeline | done | Implemented and validated through remediation commit `4ea4358` |
| F0007 | Deploy D&D campaigns and prompt assets | ansible-role-dnd-pipeline, campaigns, and narratio-prompts | done | Implemented and validated through remediation commit `7572fa3` |
| F0008 | Define opinionated D&D processing configuration | ansible-role-dnd-pipeline | done | Implemented and independently reviewed through remediation commit `3e253d7` |
| F0009 | Establish shared pipeline filesystem and execution | configuration-bearing application roles and ansible-role-dnd-pipeline | in_progress | All eight stage commits and final role integration runs passed; see `docs/roadmap/implementation.md` |
| F0010 | Integrate D&D Notarius extraction | ansible-role-notarius and ansible-role-dnd-pipeline | proposed | Depends on Feature 0009; review `docs/roadmap/features/0010-dnd-notarius-extraction-integration.md` |
| F0009 | Establish shared pipeline filesystem and execution | configuration-bearing application roles and ansible-role-dnd-pipeline | done | Implemented and independently reviewed through remediation commit `b15fe8d` |
| F0010 | Integrate D&D Notarius extraction | ansible-role-notarius and ansible-role-dnd-pipeline | proposed | Feature 0009 dependency is complete; review the roadmap before selection |
| 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 |