Document shared pipeline filesystem policy

This commit is contained in:
2026-09-14 13:02:12 +00:00
parent e63b334887
commit a7d718970f
7 changed files with 937 additions and 26 deletions

View File

@@ -0,0 +1,70 @@
# Decision 0002: Shared, Readable Pipeline Filesystem Policy
Status: accepted
Date: 2026-09-14
## Context
The D&D pipeline may be invoked either by its dedicated `narratio` service
account or by a human operator who is already a member of the `narratio`
group. Both identities need a consistent view of application configuration and
shared writable state. Notarius versions before v0.7.0 imposed private cache
modes that prevented this deployment model, but v0.7.0 delegates cache access
policy to deployment provisioning.
The pipeline processes D&D campaign material. This deployment does not treat
configuration, transcripts, caches, generated artifacts, logs, or other
pipeline content as secret. API keys and similar credentials are the sole
confidential category and must remain isolated from ordinary content.
## Decision
The suite uses `narratio` as both its service identity and shared operator
group. A human account that is already a member of that group is a supported
pipeline invocation identity. Selecting operators and managing their group
membership remain separate deployment concerns.
Application configuration directories and files are owned by
`narratio:narratio` and are world-readable. Directories normally use `0755`
and files use `0644`. They remain Ansible-managed even though the service
account owns them; operators do not edit managed configuration in place.
Standalone application roles expose generic owner, group, and mode variables
and retain independently useful defaults. The opinionated pipeline role
selects the suite ownership policy through those interfaces.
Shared writable roots use `narratio:narratio` ownership and mode `2775`.
Setgid preserves the shared group, while managed default ACLs preserve owner
and group write access and world read/traverse access for newly created
content regardless of an invoking account's ordinary umask. Ordinary files
are expected to converge to the corresponding non-executable mode `0664`.
Application source trees and installed binaries remain root-owned and
world-readable or executable as appropriate.
Credential material belongs only beneath the suite's eventual `secrets/`
directory. That directory is not world-accessible; its expected directory and
file modes are `0750` and `0640`, respectively, with
`narratio:narratio` ownership so both supported invocation identities can read
shared credentials. Configuration may contain credential reference names but
never raw credential values.
Version-controlled campaign and prompt assets may remain root-managed because
Git is authoritative, but they are world-readable. The suite does not add
confidentiality controls to non-secret D&D content.
## Consequences
The pipeline can run under the service account or an existing human member of
the shared group without maintaining separate configuration or cache trees.
The deployment must provision setgid and default ACL behavior on shared
writable roots; directory modes alone do not guarantee group write access for
content created under an arbitrary user umask.
The broad readability of transcript-derived content is intentional. Hosts
requiring confidential campaign data need a different deployment policy and
are outside this MVP contract. Secret delivery remains future work and must
honor the separate restricted subtree rather than tightening unrelated files.
Existing content with incompatible ownership or ACLs is not recursively
migrated unless a feature expressly selects that behavior. Fresh convergence
and newly created content follow this policy.

View File

@@ -6,3 +6,8 @@ change. Number records sequentially, for example
`0001-application-and-suite-role-boundaries.md`.
Do not create a decision record for routine implementation choices.
## Records
- [0001: Minimal, Module-Driven Ansible](0001-minimal-module-driven-ansible.md)
- [0002: Shared, Readable Pipeline Filesystem Policy](0002-shared-readable-pipeline-filesystem-policy.md)

View File

@@ -458,12 +458,14 @@ are complete. Feature 0008 depends on the current Narratio 2.0 ConfigKit
contract, the canonical party files deployed by Feature 0007, and prompt
definitions whose production default profiles are available from Promptkit.
Feature 0009 should adapt the validated D&D Notarius pipeline, remove its
Feature 0010 should adapt the validated D&D Notarius pipeline, remove its
hard-coded campaign references in favor of Narratio invocation bindings,
declare its runtime-directory policy, map its accepted outputs into Narratio,
and enable extraction. Later features should address storage/publishing and
secret delivery together, operator access, collection assembly, and an
end-to-end workflow that can use actual external services.
and enable extraction after Feature 0009 establishes shared filesystem and
execution policy. Later features should address storage/publishing and secret
delivery together, optional operator selection and membership management,
collection assembly, and an end-to-end workflow that can use actual external
services.
## Potential Future Hardening

View File

@@ -0,0 +1,266 @@
# Feature 0009: Shared Pipeline Filesystem and Execution
Status: proposed
## Summary
Establish one coherent filesystem and invocation policy for the D&D suite.
Standalone application roles will expose sensible generic configuration
ownership and mode controls, while the pipeline role will use those controls
to make configuration service-owned and world-readable and to make writable
state safely shareable by the service account and existing human members of
its group.
## Problem or Opportunity
The current standalone roles hard-code their configuration ownership and
modes. Those defaults are reasonable in isolation, but the pipeline cannot
select its intended `narratio:narratio` ownership without adding a second
convergence pass that would fight the dependency roles and report changes on
every run.
Narratio's writable roots already use setgid mode `2775`, but directory mode
alone does not preserve group write access when different invocation identities
have different umasks. Notarius v0.7.0 has removed its application-enforced
private cache modes, so deployment provisioning can now establish a consistent
shared policy before Notarius integration begins.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the generic role
interfaces, direct module-driven convergence, and suite overrides.
- [The testing house style](../../testing.md) governs behavioral access tests
and clean repeated convergence.
- [The MVP roadmap](../mvp.md) assigns operator access and cross-application
policy to the pipeline role while keeping standalone roles independently
useful.
- [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md)
requires direct idempotent modules without preliminary state inspection.
- [Decision 0002](../../decisions/0002-shared-readable-pipeline-filesystem-policy.md)
defines the service ownership, shared writable state, world-readable content,
and restricted credential boundary implemented by this feature.
## Scope
- Add configuration owner, group, directory-mode, and file-mode variables to
the Audita, Notarius, Narratio, and Scriptorium roles.
- Preserve standalone defaults appropriate to each application rather than
embedding D&D suite policy in those roles.
- Add suite-level runtime identity and configuration-mode variables to the
pipeline role and pass them explicitly to all four configuration-bearing
dependencies.
- Run the Narratio dependency before the other application dependencies so it
creates the selected service account and group before they write
service-owned configuration.
- Converge suite application configuration as `narratio:narratio`, with
directory mode `0755` and file mode `0644` by default.
- Keep `/var/lib/narratio`, `/var/spool/narratio`, and
`/var/cache/narratio` as `narratio:narratio` mode `2775` shared writable
roots.
- Install the Ubuntu `acl` package, declare a pinned `ansible.posix`
collection dependency, and manage access and default ACL entries that retain
owner/group write and world read/traverse access beneath shared roots.
- Support invocation as either the service account or an existing human
member of the selected runtime group.
- Document the standalone defaults, pipeline overrides, expected group
membership, world-readable non-secret boundary, and reserved restricted
`secrets/` policy.
- Add focused integration coverage for public configuration-mode overrides,
cross-identity access, and immediate clean repeated convergence.
## Non-goals
- Upgrading Notarius, adding its ConfigKit import interface, deploying its
D&D pipeline, creating `/var/cache/notarius`, or enabling Narratio's
extraction stage; those belong to Feature 0010.
- Changing any application's native configuration fields or runtime behavior.
- Selecting human operators or changing their group membership.
- Creating or populating a `secrets/` directory, delivering credentials, or
defining secret injection.
- Making application configuration group-writable or supporting manual edits
to Ansible-managed configuration.
- Changing ownership of root-managed source checkouts, installed binaries,
campaign assets, or prompt assets.
- Recursively migrating pre-existing runtime content with incompatible modes
or ACLs.
- Running transcript processing, calling external services, or adding
scheduling and service management.
## Target End State
Each standalone role exposes the same four concepts using its application
prefix. Its defaults remain appropriate for an independent installation:
| Role | Configuration owner | Configuration group | Directory mode | File mode |
| --- | --- | --- | --- | --- |
| Audita | `root` | `root` | `0755` | `0644` |
| Notarius | `root` | `root` | `0755` | `0644` |
| Scriptorium | `root` | `root` | `0755` | `0644` |
| Narratio | `root` | `narratio` | `0750` | `0640` |
For example, the Notarius variables are
`notarius_config_owner`, `notarius_config_group`,
`notarius_config_directory_mode`, and `notarius_config_file_mode`; the other
roles use their corresponding prefixes. Each role uses these variables in the
ordinary directory and template tasks that already own its configuration. No
role adds a follow-up permission-repair task or preliminary inspection.
The pipeline role defines `dnd_pipeline_runtime_user` and
`dnd_pipeline_runtime_group`, both defaulting to `narratio`, plus
`dnd_pipeline_config_directory_mode: "0755"` and
`dnd_pipeline_config_file_mode: "0644"`. It passes those values as the four
roles' configuration owner, group, and mode inputs. Narratio executes first in
dependency order and creates the selected identity before another dependency
references it.
The resulting application configuration beneath
`/usr/local/etc/{audita,notarius,narratio,scriptorium}` is owned by
`narratio:narratio` and is world-readable. It remains under Ansible control;
neither the service account nor human operators are expected to edit managed
files in place.
The three existing Narratio writable roots are `narratio:narratio` mode
`2775`. Their access and default ACLs are equivalent to `u::rwx`, `g::rwx`,
`o::r-x`, and `m::rwx`. Inherited permissions remain subject to the mode
requested for each new file type, so ordinary files are non-executable while
remaining group-writable and world-readable. A later feature applies the same
policy when it introduces another shared root such as
`/var/cache/notarius`.
A human account already belonging to `narratio` can use the same configuration
and writable roots as the service account. This feature does not choose that
account. Credential files are absent; the reserved future
`/usr/local/etc/narratio/secrets` subtree uses the distinct `0750` directory
and `0640` file policy when a credential-delivery feature creates it.
## Repository Ownership
- `ansible-role-audita`, `ansible-role-notarius`, and
`ansible-role-scriptorium` own their generic configuration ownership and
mode variables, standalone defaults, documentation, and focused integration
coverage.
- `ansible-role-narratio` owns the equivalent generic controls while retaining
its existing standalone relationship to the service group it creates.
- `ansible-role-dnd-pipeline` owns dependency ordering, the suite runtime
identity and configuration-mode defaults, explicit dependency overrides,
the `acl` package and `ansible.posix` dependency, shared-root ACL
convergence, consumer documentation, and cross-identity integration
coverage.
- `ansible-workspace-dnd` owns this roadmap, Decision 0002, the later staged
implementation plan, and aggregate status.
- The five application source repositories are unchanged; their runtime
contracts are not needed to implement configuration-file ownership.
## Constraints and Settled Decisions
- Standalone application roles remain independently usable. Their defaults do
not assume that a `narratio` account exists unless the role itself creates
it.
- The pipeline role selects suite policy by passing public role variables; it
does not reapply ownership after dependencies have completed.
- Configuration owner and group variables are strings, while mode variables
use the quoted four-digit strings expected by Ansible file-management
modules.
- The pipeline's selected runtime user and group are the configuration owner
and group. Supporting different configuration and runtime identities would
require a concrete later use case.
- Application configuration is world-readable but not group-writable. Shared
writable roots and their ordinary content are group-writable and
world-readable.
- The role uses `ansible.builtin.apt` for the `acl` package and
`ansible.posix.acl` for access/default ACL state. The collection dependency
is pinned in the pipeline role's manifest and installed by its integration
driver.
- ACL management covers only the three existing writable roots and their
inheritance policy. It does not recursively rewrite existing descendants.
- A `secrets/` subtree is a documented future boundary, not state created by
this feature.
- Tests exercise the public operating contract and one representative
cross-identity workflow. They do not enumerate every path or restate every
module argument.
## Simplest Viable Implementation
1. Add four defaults, four argument-specification entries, and direct task
substitutions to each configuration-bearing standalone role; update its
README and focused integration inputs without adding new task flow.
2. Reorder the pipeline dependencies so Narratio creates the service identity
first, add four suite policy variables, and pass them directly to each
configuration-bearing role.
3. Add the pinned `ansible.posix` requirement, install `acl`, and apply the
selected access/default ACL entries to the three existing writable roots
with ordinary state-management modules.
4. Update pipeline consumer documentation and extend its integration driver
with one representative human group member, native configuration
inspection, shared-write behavior, and a clean repeat.
No task gathers preliminary filesystem or account state. Existing `file`,
`template`, `apt`, and `acl` modules own convergence and change reporting.
## Rationale and Alternatives
Public ownership and mode variables let each standalone role express its own
sensible installation while allowing a composing role to select different
policy through normal Ansible precedence. A corrective pipeline task would
fight the dependency templates and make every otherwise unchanged run report
changes.
Setgid alone preserves group identity but does not guarantee group-write bits
for files created under an arbitrary human user's umask. A managed default ACL
expresses the required inherited state directly. A wrapper command that sets a
umask would add another invocation path and would not protect direct use of the
installed applications.
Mode `2775`, rather than `2770`, is deliberate: D&D transcript content is not
treated as secret in this deployment. Only API keys and similar credentials
belong in the separately restricted future subtree.
## Acceptance Criteria
- Each configuration-bearing standalone role exposes and documents owner,
group, directory-mode, and file-mode variables with the standalone defaults
listed above.
- Each role applies those inputs through the tasks that already create its
configuration directory and file, without a second convergence pass.
- The pipeline role runs Narratio first and explicitly selects
`narratio:narratio`, `0755` directories, and `0644` files for all application
configuration.
- The deployed configuration for Audita, Notarius, Narratio, and Scriptorium
is owned by `narratio:narratio`, is readable by other local users, and
contains no credential values.
- The three existing Narratio writable roots are `narratio:narratio` mode
`2775` and have access/default ACLs that preserve group write and world
read/traverse access for new content.
- The pipeline role declares a pinned `ansible.posix` dependency and installs
the required Ubuntu `acl` package.
- The service account and a representative existing human member of the
`narratio` group can use the same configuration and exchange ordinary
writable-state content.
- The role does not create users other than the established service account,
alter human group membership, create a secrets directory, or migrate
existing descendants recursively.
- Syntax checking and production-profile lint pass in every changed role.
- Focused standalone-role integration checks and the complete pipeline
integration entry point pass.
- An immediate repeated application in every changed role reports no changes.
- Tests observe the shared operating contract without snapshotting defaults,
enumerating implementation steps, or testing trusted module behavior.
## Dependencies and Follow-up Work
Features 0001 through 0008 and the standalone-role test-suite simplification
are complete. Notarius v0.7.0's deployment-owned cache permissions remove the
application blocker that previously prevented this policy, but Feature 0009
does not otherwise depend on or modify the Notarius application.
Feature 0010 applies this policy to `/var/cache/notarius` while adding the D&D
extraction integration. Later work may add optional operator-selection and
group-membership variables or deliver credentials beneath the restricted
`secrets/` subtree.
## Potential Future Hardening
- Offer a non-world-readable deployment profile if a concrete environment
later treats campaign material as confidential.
- Select a recursive migration policy if supported upgrades must normalize
pre-existing descendants rather than only managed roots and new content.

View File

@@ -0,0 +1,529 @@
# Feature 0010: D&D Notarius Extraction Integration
Status: proposed
## Summary
Enable Narratio's Notarius stage with the maintained ten-lane D&D extraction
pipeline. The pipeline role will supply the opinionated Notarius pipeline,
bind campaign-owned inputs through Narratio's invocation boundary, and declare
the exact lane contracts Narratio may accept as extraction sources. It uses
the service ownership and shared-access foundation established by Feature
0009.
## Problem or Opportunity
Features 0006 through 0008 install and configure the five applications,
deploy the D&D content, and define the transcript-processing and Scriptorium
workflow. Narratio still leaves its Notarius stage disabled, and Notarius's
managed configuration contains no pipeline. A run can therefore produce a
cleaned and trimmed transcript but cannot yet extract the structured D&D
registries and events implemented by Notarius.
The uploaded test-machine configuration demonstrates the intended multi-step
pipeline, but it embeds campaign-specific filesystem paths and explicit
runtime roots. The current Notarius v0.7.0 complete example and Narratio 2.0
integration contract supersede those details. In particular, Narratio must
prepare invocation-local campaign references and own the run-specific output
staging directory; generated registry and event handoffs remain internal to
Notarius. Notarius v0.7.0 also replaces configuration version 4 with a strict,
ConfigKit-backed version 5 contract and makes cache access policy a deployment
responsibility.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the suite-owned public
interface, direct desired-state configuration, and reliance on the
standalone roles' native templates.
- [The testing house style](../../testing.md) governs focused native contract
validation and immediate clean repeated convergence.
- [The MVP roadmap](../mvp.md) assigns opinionated D&D policy and
cross-application coordination to the pipeline role while keeping the
standalone application roles generic.
- [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md)
requires module-owned convergence without redundant inspection or
supplemental state.
- [Decision 0002](../../decisions/0002-shared-readable-pipeline-filesystem-policy.md)
defines the service ownership, shared operator access, world-readable
content, and restricted credential boundary.
- [Feature 0008](0008-opinionated-dnd-processing-configuration.md) establishes
the trimmed transcript, ConfigKit layout, and `testing` overlay into which
this feature integrates.
- [Feature 0009](0009-shared-pipeline-filesystem-and-execution.md) establishes
the runtime identity, configuration ownership interfaces, and inherited
shared-access policy extended by this feature.
## Scope
- Update the standalone Notarius role for Notarius v0.7.0 and configuration
version 5 while preserving its generic, independently usable interface.
- Expose Notarius's native `configkit.imports` field through one optional
`notarius_configkit_imports` role variable; the role continues to own only
its root configuration and does not manage caller-selected fragments.
- Supply one complete `dnd-session` Notarius pipeline as deliberate D&D suite
policy in a suite-managed imported fragment at
`/usr/local/etc/notarius/pipelines/dnd-session.yml`.
- Adapt the maintained Notarius v0.7.0 complete D&D pipeline using canonical
version 5 module-binding objects, including:
- the embedded `dnd-extraction` PromptKit workload profile;
- Seriatim input and scene-based chunking;
- the ordered `describe-session`, `extract-events`, and `track-enemies`
steps;
- all ten maintained D&D artifact lanes and their generated handoffs; and
- JSON output with the chunk map and selected evidence context.
- Remove every campaign-specific filesystem reference from the Notarius
pipeline definition.
- Enable Narratio's Notarius stage and select `dnd-session`.
- Bind `party`, `players`, and `glossary` to Narratio's prepared campaign
sources at invocation time.
- Define Narratio acceptance descriptors for all ten maintained lane outputs.
- Make the pipeline map, Narratio reference map, and Narratio output map
ordinary suite variables so callers can compose or replace native mappings
through inventory precedence.
- Make the selected pipeline ID an ordinary suite variable and keep it
coordinated with the default pipeline map.
- Enable Notarius caching to the maximum currently available extent: use
`auto` chunk-plan caching and enable checkpoint recording. Narratio does not
yet request checkpoint reuse with Notarius's `--resume` flag.
- Provision `/var/cache/notarius` as a shared FHS cache root owned by
`narratio:narratio` with mode `2775`, with chunk-plan and checkpoint stores
beneath it.
- Apply Feature 0009's established access and default ACL policy to the new
cache root so content created by either supported invocation identity remains
group-writable and world-readable.
- Keep Notarius enabled under the existing `testing` overlay. Testing and
production select the same Notarius pipeline and workload profile until the
suite chooses a distinct testing profile strategy.
- Document the reference boundary, lane-to-source mapping, runtime-state
policy, production/testing behavior, and supported caller customization.
- Extend focused integration coverage for native Notarius validation,
Narratio base/testing resolution, representative reference and output
wiring, and immediate clean repeated convergence.
## Non-goals
- Changing any application's native configuration fields or duplicating a
standalone role's root configuration template in the pipeline role.
- Making the standalone Notarius role manage imported fragments; fragment
deployment remains the responsibility of the caller that selects an
import.
- Copying the uploaded test-machine configuration verbatim.
- Installing a filesystem PromptKit profile for Notarius. Notarius v0.7.0
already embeds the selected production `dnd-extraction` fallback profile.
- Defining a second Notarius pipeline solely to select an inexpensive testing
model, or otherwise adding profile inheritance that Notarius does not
natively provide.
- Binding a spell catalog before the campaign registry declares one.
- Publishing, rendering, or otherwise consuming the new extraction sources in
Scriptorium artifacts.
- Selecting a default campaign.
- Delivering API keys, provider credentials, environment files, or a general
secret-management mechanism.
- Running Notarius extraction, making model calls, or processing a complete
transcript during integration tests.
- Managing output retention, cache cleanup, or debug retention.
- Adding checkpoint-resume control to Narratio or changing Narratio's
subprocess invocation to pass `--resume` or `--config-profile`.
- Installing a systemd service, timer, scheduler, or other unattended
invocation mechanism.
- Selecting human operator accounts or changing their membership in the
`narratio` group.
- Revising the general configuration ownership, dependency ordering, ACL
dependency, or existing shared roots established by Feature 0009.
- Delivering or populating the future restricted `secrets/` directory.
- Modifying upstream application source, embedded Notarius prompts, schemas,
modules, codecs, or validators.
- Collection assembly, role releases, storage/publishing, upgrade/removal
behavior, or end-to-end production validation.
## Target End State
The standalone Notarius role continues to own the version 5 root document at
`/usr/local/etc/notarius/config.yml`. Its public interface exposes the native
`configkit.imports` list, and the pipeline role selects the explicit relative
import `pipelines/dnd-session.yml`. The pipeline role owns that fragment and
renders the complete `dnd_pipeline_notarius_pipelines` map into it, producing
one native `dnd-session` definition by default. The definition follows the
Notarius v0.7.0 maintained complete D&D topology:
```text
Seriatim transcript
-> dnd/scenes chunking
-> describe-session
item-registry
npc-registry
location-registry
scene-descriptions
-> extract-events
item-occurrences
spells
combat-turns
npc-occurrences
location-occurrences
-> track-enemies
enemy-events
-> JSON bundle, chunk map, and evidence context
```
Feature 0009 already makes application configuration service-owned and
world-readable. The Notarius root document and new suite fragment retain that
`narratio:narratio`, `0755` directory, and `0644` file policy through the
standalone role's established ownership and mode interface.
The `extract-events` step consumes the four generated outputs from
`describe-session` under their declared internal reference slots. The
`track-enemies` step consumes the generated NPC registry and scene
descriptions from `describe-session` and the generated combat turns and NPC
occurrences from `extract-events`. Those handoffs are part of the Notarius
pipeline and never appear in Narratio's CLI reference map.
Narratio's effective base configuration enables Notarius, selects the managed
configuration and `dnd-session`, and supplies three campaign-owned references:
| Notarius selector | Prepared Narratio source |
| --- | --- |
| `party` | `narratio.input.party` |
| `players` | `narratio.input.players` |
| `glossary` | `narratio.input.glossary` |
Narratio snapshots those inputs for each invocation and passes their absolute
paths with `--reference`. No campaign path appears in Notarius configuration.
The optional `spell_catalog` binding is absent because neither deployed
campaign currently declares `inputs.spell_catalog_file`. A caller that adds
that campaign input can extend the suite reference map with
`spell_catalog: narratio.input.spell_catalog` without changing either
application role.
Narratio accepts all ten configured lanes using these exact v1 contracts and
registers each accepted payload as `narratio.extraction.<output-key>`:
| Narratio output key | Lane ID | Schema ID | Module key |
| --- | --- | --- | --- |
| `item_registry` | `item-registry` | `notarius.dnd.item_registry` | `dnd/item-registry` |
| `npc_registry` | `npc-registry` | `notarius.dnd.npc_registry` | `dnd/npc-registry` |
| `location_registry` | `location-registry` | `notarius.dnd.location_registry` | `dnd/location-registry` |
| `scene_descriptions` | `scene-descriptions` | `notarius.dnd.scene_descriptions` | `dnd/scene-descriptions` |
| `item_occurrences` | `item-occurrences` | `notarius.dnd.item_occurrences` | `dnd/item-occurrences` |
| `spells` | `spells` | `notarius.dnd.spells` | `dnd/spells` |
| `combat_turns` | `combat-turns` | `notarius.dnd.combat_turns` | `dnd/combat-turns` |
| `npc_occurrences` | `npc-occurrences` | `notarius.dnd.npc_occurrences` | `dnd/npc-occurrences` |
| `location_occurrences` | `location-occurrences` | `notarius.dnd.location_occurrences` | `dnd/location-occurrences` |
| `enemy_events` | `enemy-events` | `notarius.dnd.enemy_events` | `dnd/enemy-events` |
Every entry requires `media_type: application/json` and
`schema_version: v1`. Narratio validates the received descriptor before
registering the source; it does not infer contracts from filenames.
Narratio supplies its run-specific staging root through Notarius's
`--output-dir` override, so the suite does not set Notarius's global
`output.directory`. Reconstructible Notarius state uses the FHS cache layout:
```text
/var/cache/notarius/
├── chunk-plans/
└── checkpoints/
```
The pipeline role creates the root as `narratio:narratio` mode `2775`, sets
chunk-plan mode to `auto`, enables checkpoint recording, and configures both
child paths. Notarius creates cache entries with conventional maximum creation
modes and leaves their effective modes to deployment provisioning, process
umask, setgid inheritance, and default ACLs. The suite applies a default ACL
that retains owner and group write access and world read/traverse access for
new cache content. Narratio and its Notarius subprocess may run as the
dedicated `narratio` account or as a human member of the `narratio` group.
Chunk plans are reused automatically; checkpoints are recorded but are not
reused because Narratio does not pass `--resume`. The debug root remains
unset. The selected Notarius process working directory is
`/usr/local/etc/notarius`, matching the managed configuration location; no
relative profile or reference paths depend on it.
The cache root receives the same setgid and default-ACL policy that Feature
0009 applies to Narratio's existing shared roots. Non-secret content created
beneath it remains writable by the shared group and readable by other local
users. The suite does not create or populate a `secrets/` directory.
The base Narratio configuration and the `testing` ConfigKit overlay both run
the extraction stage using Notarius's embedded `dnd-extraction` profile. The
testing overlay continues to override only the Scriptorium profile selections;
it does not disable or restate Notarius. A later feature may select a distinct
inexpensive Notarius testing profile without changing the pipeline topology.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the D&D pipeline map and imported fragment,
Narratio integration mappings, Notarius dependency-variable wiring, the new
cache root and its inherited shared-access policy, testing-overlay choice,
consumer documentation, and suite integration coverage.
- `ansible-role-notarius` owns the generic Notarius v0.7.0 installation,
version 5 root configuration, optional ConfigKit import interface, focused
role documentation, and role-local integration coverage. It does not own or
render the suite's imported D&D fragment.
- `ansible-role-audita`, `ansible-role-narratio`, and
`ansible-role-scriptorium` remain unchanged. The Narratio role owns its generic
Notarius adapter fields and ConfigKit-aware root configuration.
- `../notarius` is the read-only authority for configuration version 5, the
maintained D&D pipeline, embedded profile, module handoffs, and lane
contracts.
- `../narratio` is the read-only authority for prepared campaign sources,
subprocess invocation, output acceptance, and profile overlay behavior.
- `assets/configs/notarius/config.yml` is an operational reference only. Its
useful topology is adapted, while its campaign paths and runtime roots are
not copied.
- `assets/campaigns` remains unchanged and continues to own the campaign
registry inputs that Narratio prepares.
- `ansible-workspace-dnd` owns this roadmap, the later implementation plan,
settled MVP decisions, and aggregate status.
## Constraints and Settled Decisions
- The selected application contracts are Notarius v0.7.0 and Narratio v2.0.0,
matching the pipeline role's pinned application versions.
- Feature 0009 has already established the runtime identity, dependency order,
standalone ownership interfaces, configuration modes, `acl` package, and
pinned `ansible.posix` dependency used here.
- The pipeline role relies on the standalone roles for application
installation and both root configuration documents. It manages only the
suite-owned Notarius and Narratio fragments selected through those public
interfaces.
- The standalone Notarius role defaults to configuration version 5 and exposes
`notarius_configkit_imports` as the complete native import list. A null value
omits the `configkit` section and leaves composition with Notarius.
- The pipeline role passes the fixed import
`pipelines/dnd-session.yml` to the standalone role and manages that imported
file as suite-owned configuration. It does not pass the pipeline map into
the standalone role's root-level `notarius_pipelines` field.
- `/var/cache/notarius` uses the Feature 0009 runtime identity, mode `2775`,
and access/default ACL entries equivalent to `u::rwx`, `g::rwx`, `o::r-x`,
and `m::rwx`.
- `dnd_pipeline_notarius_pipelines` is a complete native map whose default
contains `dnd-session`. Callers may replace it or compose additional
pipeline definitions with Jinja's `combine` filter in inventory.
- `dnd_pipeline_narratio_notarius_pipeline_id` defaults to `dnd-session`.
Callers that replace that key are responsible for selecting a matching ID.
- `dnd_pipeline_narratio_notarius_references` is the complete native Narratio
reference map. It defaults to `party`, `players`, and `glossary`; its values
are prepared source IDs, never filesystem paths.
- `dnd_pipeline_narratio_notarius_outputs` is the complete native Narratio
output map. It defaults to all ten lanes because the suite claims to consume
the complete maintained D&D extraction workflow.
- `dnd_pipeline_notarius_cache_root` defaults to `/var/cache/notarius`,
`dnd_pipeline_notarius_cache_chunk_plans_mode` defaults to `auto`, and
`dnd_pipeline_notarius_cache_checkpoints_enabled` defaults to `true`. They
are intentional, inventory-overridable suite policy. The two application
cache directories derive from that root rather than becoming independent
suite variables.
- The pipeline defaults to `llm_profile: dnd-extraction` and relies on
Notarius's embedded fallback. It does not set `promptkit.profile_file`,
`promptkit.profile_dir`, a local backend, or credentials.
- The pipeline uses the version 5 `input: {module: seriatim}` binding,
`dnd/scenes` chunking with two retries, and the three ordered steps documented
above. Extract, merge, and normalize bindings use canonical objects with
`module:`; retries and generated reference handoffs match the maintained
Notarius complete example.
- JSON output enables `include_chunk_map` and evidence context with a
three-unit window. Evidence context includes item occurrences, item
registry, location registry, location occurrences, NPC registry, spells,
combat turns, NPC occurrences, and enemy events, matching the maintained
example.
- Notarius pipeline YAML contains no external file references. Narratio owns
all campaign input materialization for the orchestrated path.
- Narratio's Notarius binary and configuration paths remain the established
`/usr/local/bin/notarius` and `/usr/local/etc/notarius/config.yml`.
- The suite uses the runtime user and group selected by Feature 0009 for the
Notarius cache and configuration fragment.
- Narratio's Notarius working directory is explicitly
`/usr/local/etc/notarius`; the timeout inherits Narratio's native three-hour
default because the suite has selected no different policy.
- Narratio owns per-run Notarius output staging. The suite provisions
`/var/cache/notarius` for the shared `narratio` identity, and Notarius owns
its child cache stores. The role does not create `/var/lib/notarius`, set a
global output root, or provision a debug root.
- Checkpoint enablement records reusable state but does not cause Narratio to
reuse it. Resume remains an explicit Notarius invocation action and requires
a later Narratio integration decision.
- The production configuration enables Notarius. The existing `testing`
overlay inherits that enabled stage and the same `dnd-extraction` profile;
it does not override Notarius merely to avoid model calls.
- All maps use native application shapes and remain replaceable through normal
inventory precedence. The suite does not create field-by-field aliases for
every nested lane or module option.
- Directory and ACL tasks declare only the shared roots required by the
applications, using ordinary state-management modules with task-level
privilege escalation. No `stat`, command, handler, checksum, manifest, or
production validation task accompanies them.
## Simplest Viable Implementation
The production changes remain direct configuration management:
1. Update the standalone Notarius role's version and configuration-version
defaults and add the nullable native ConfigKit import field to defaults,
argument specification, root template, and documentation. Cover that public
behavior with focused native validation and a clean repeat.
2. Add the selected Notarius pipeline map, shared FHS cache policy, and three
suite-level Narratio integration mappings to pipeline-role defaults and the
argument specification.
3. Pass the fixed import and cache choices to `rakestraw.notarius`, and pass
Notarius enablement, selected ID, working directory, references, and outputs
to `rakestraw.narratio`.
4. Create the Notarius pipeline-fragment directory and cache root with ordinary
`ansible.builtin.file` tasks, render the suite-owned pipeline map into one
imported fragment, and extend Feature 0009's access/default ACL task to the
new root.
5. Update both role READMEs and extend focused integration coverage with native
configuration validation, effective-configuration inspection, inspection
as a supported group member, and clean repeats.
The standalone roles' template operations continue to own both root
configuration files. The pipeline role adds one Notarius pipeline-fragment
template but does not duplicate the root document or change the existing
Narratio testing-overlay template for this feature.
## Rationale and Alternatives
Using Notarius's maintained complete example preserves the upstream module
topology and contract while keeping suite policy explicit. Maintaining a
smaller custom pipeline would make the role responsible for deciding which
D&D artifacts no longer matter. Copying the uploaded file would instead
preserve obsolete host paths and bypass Narratio's verified reference
boundary.
Rendering one native map into a ConfigKit-imported fragment keeps configuration
ownership clear and preserves the inventory-composition workflow already
selected for Notarius. It also follows Notarius v0.7.0's maintained composition
shape without making the generic role own D&D content. Field-specific variables
for every lane, step, and retry would create a large parallel schema with little
consumer value. One complete map is easier to replace, combine, validate, and
compare with Notarius documentation.
`/var/cache/notarius` follows the filesystem hierarchy's intended location for
reconstructible application state and is preferable to the uploaded
`/var/lib/notarius/cache` layout. Assigning the root to the dedicated
`narratio` account and group gives unattended and human-initiated runs one
reusable cache. Mode `2775` preserves the shared group, and the default ACL
prevents an invoking account's umask from accidentally removing group write or
world read access from new content. Notarius v0.7.0 respects this deployment
policy rather than replacing it with application-owned private modes.
Narratio's staging root remains separate because output bundles are run
results, not cache data.
The `testing` overlay cannot natively replace a nested Notarius pipeline's
`llm_profile`; that configuration lives in a separate application file.
Duplicating the full pipeline or managing a second Notarius root configuration
would add substantial configuration drift for one model choice. Testing
therefore inherits production extraction for now; a distinct testing strategy
can be selected later if it becomes a concrete need.
## Acceptance Criteria
### Required Configuration Behavior
- The pipeline role installs a Notarius configuration that natively validates
the `dnd-session` pipeline without provider credentials or a model call.
- The standalone Notarius role supports an explicitly selected v0.7.0,
emits configuration version 5 with its compatible defaults, and can render
a caller-supplied native ConfigKit import list.
- The root Notarius configuration imports the suite-owned
`pipelines/dnd-session.yml` fragment, and that fragment contains the complete
pipeline map selected through inventory.
- The pipeline contains the maintained Seriatim input, D&D scene chunker,
three ordered steps, ten lanes, generated handoffs, JSON chunk map, and
selected evidence-context policy.
- The Notarius configuration contains no campaign-specific reference paths,
PromptKit operator-profile path, fixed output root, or debug root.
- The Notarius configuration selects `auto` chunk-plan caching, enables
checkpoints, and uses `/var/cache/notarius/chunk-plans` and
`/var/cache/notarius/checkpoints` respectively.
- The deployed cache root is `narratio:narratio` mode `2775`; its access and
default ACLs preserve group write and world read/traverse access without
depending on Notarius to enforce entry modes. Checkpoints are recorded; the
roadmap does not claim Narratio reuses them.
- The Notarius root configuration and suite-owned imported fragment retain
Feature 0009's `narratio:narratio`, `0755` directory, and `0644` file policy.
No secret value appears in either file.
- Narratio's effective base configuration enables Notarius, selects
`dnd-session`, and uses the installed binary, configuration, and working
directory.
- Narratio maps `party`, `players`, and `glossary` to the three documented
prepared campaign sources and contains no default `spell_catalog` binding.
- Narratio declares all ten documented output entries with exact lane, media,
schema, version, and module identities.
- Narratio natively validates the effective base configuration for either
deployed campaign without a model call.
- `narratio config show` or the equivalent native inspection surface exposes
the enabled stage, selected pipeline, representative reference, and
representative output contract.
- The effective `testing` profile keeps Notarius enabled with the same pipeline
and profile while retaining the existing Scriptorium testing overrides.
- A caller can compose an additional Notarius pipeline into
`dnd_pipeline_notarius_pipelines` and select it through the corresponding
Narratio pipeline-ID variable without changing the role.
- A caller can add the optional spell-catalog source by extending the native
Narratio reference map after providing that campaign input.
- An immediate repeated role application with unchanged inputs reports no
changes.
- The production role contains no new configuration probes, validation
commands, runtime state beyond the required cache root, state bookkeeping,
duplicated root templates, secrets, extraction invocation, storage, or
publishing behavior.
### Required Validation
- YAML syntax checking and production-profile ansible-lint pass for the role
and test playbooks.
- The standalone-role integration suite explicitly selects Notarius v0.7.0,
validates a representative imported version 5 configuration through the
native CLI, and retains immediate clean repeated convergence without
asserting that v0.7.0 remains the default forever.
- The complete existing pipeline integration entry point continues to install
the pinned role combination and validate both deployed campaigns.
- A representative human account in the `narratio` group can execute native
Notarius configuration inspection through the same files used by the service
account.
- Notarius natively validates the role-managed `dnd-session` configuration.
- Notarius `config effective` exposes the composed imported pipeline and a
representative cache override without parsing managed YAML directly.
- Narratio natively validates both base and `testing` configurations with an
explicitly selected deployed campaign.
- Focused native inspection observes a representative generated Notarius
handoff and representative Narratio reference and output mappings rather
than reproducing the full application validators in shell assertions.
- A test explicitly supplies a small additional or replacement Notarius
pipeline mapping and observes that selected behavior; it does not assert
that `dnd-session` remains the role's current default forever.
- A representative test explicitly overrides one cache choice and observes
the effective Notarius configuration; it does not freeze all current cache
defaults or test Notarius's cache implementation.
- The immediate repeat reports `changed=0` and `failed=0`.
- Tests do not execute extraction, call an LLM, snapshot complete rendered
files, enumerate every nested option as an implementation lock, inspect
template task results, test filesystem metadata, or reproduce Ansible,
Notarius, Narratio, ConfigKit, or PromptKit behavior.
## Dependencies and Follow-up Work
Features 0001 through 0008 and the standalone-role test-suite simplification
are complete. Implementation of this feature depends on completing Feature
0009's shared filesystem and execution policy. It also depends on the current
Notarius v0.7.0 maintained D&D configuration and ConfigKit contract, Narratio
v2.0.0 subprocess contract, campaign sources deployed by Feature 0007, and
trimmed transcript policy defined by Feature 0008.
The next suite feature should select which extraction sources feed new or
existing Scriptorium artifacts, or address pipeline-wide credential delivery
if real end-to-end execution requires it first. Later work should cover
storage and publishing, optional operator selection and membership management,
collection assembly, release pinning, and an end-to-end workflow using actual
external services. A separate feature may add inexpensive Notarius testing
extraction if a concrete workflow justifies a second operator profile or
application configuration.
## Potential Future Hardening
- Add explicit cache and debug retention policy once operational use provides
concrete retention requirements.
- Define credential delivery beneath the restricted `secrets/` subtree. No
further Notarius cache-permission feature is required for shared invocation.
- Pin content repositories to immutable releases when their upstream projects
begin publishing them.

View File

@@ -14,9 +14,11 @@ Build independently usable Ansible roles for the five Narratio applications
and compose them through a suite-level role developed in its own repository.
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. Human operators invoke
Narratio commands directly to process D&D session recordings and produce
transcripts and related artifacts.
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.
## Locked Decisions
@@ -224,24 +226,40 @@ application-role releases in one source repository.
- 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 the suite's application configuration and
writable runtime directories; `narratio` is also the shared operator group.
- Application source trees and installed binaries are owned by `root` and are
not writable by operators or the runtime account.
- Ordinary human users run `narratio run` and other Narratio commands directly.
- Those operators receive the required access by membership in the `narratio`
group.
- Narratio's configuration directory is owned by `root:narratio` with mode
`0750`, and its pipeline file is owned by `root:narratio` with mode `0640`.
Configuration remains under Ansible control rather than being routinely
edited by operators on the host.
- The Narratio workspace, spool, and cache roots are owned by
`narratio:narratio` with mode `2775`, preserving the group on created content
and granting the shared write access needed for direct operator invocations.
- The 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.
- 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
being routinely edited by operators on the host.
- Workspace, spool, and cache roots are owned by `narratio:narratio` with mode
`2775`. Setgid and managed default ACLs preserve shared group write access
and world read/traverse access for newly created directories and files even
when invocation identities have different ordinary umasks.
- The pipeline role installs the host `acl` package and uses the declared,
pinned `ansible.posix` collection to manage access and default ACL entries on
those shared writable roots.
- 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.
Its content is world-readable but is populated by the suite role and is not
edited directly on the managed host.
- Configuration, transcripts, caches, generated artifacts, logs, campaign
data, and prompt assets are deliberately non-secret D&D content and remain
world-readable. API keys and similar credentials are the sole confidential
category.
- Debug output is not enabled by the MVP. Any later debug feature must either
produce world-readable non-secret D&D diagnostics or identify and justify a
narrower application contract before deployment.
- Credential material will live beneath a restricted `secrets/` subdirectory
owned by `narratio:narratio`, with directories mode `0750` and files mode
`0640`. Ordinary configuration contains only credential reference names.
- [Decision 0002](../decisions/0002-shared-readable-pipeline-filesystem-policy.md)
records the complete rationale and boundary for this policy.
### Narratio configuration
@@ -287,6 +305,20 @@ application-role releases in one source repository.
Scriptorium artifacts and families. Audita initially uses the same endpoint
and models in production and testing; identical values are inherited rather
than duplicated in the overlay.
- The D&D suite enables Notarius's `auto` chunk-plan cache and checkpoint
cache beneath `/var/cache/notarius`. That FHS cache root is owned by the
`narratio` account and group with mode `2775` and the suite's shared default
ACL policy. Notarius v0.7.0 leaves cache-entry access to that deployment
policy. Chunk plans are reused automatically; checkpoints are recorded but
Narratio does not yet request their reuse.
- The standalone Notarius role exposes Notarius v0.7.0's native ConfigKit
import list while remaining independent of D&D content. The pipeline role
owns an imported `pipelines/dnd-session.yml` fragment containing its
opinionated, inventory-composable D&D pipeline map; the standalone role
continues to own only the version 5 root document.
- The Narratio `testing` profile keeps the Notarius stage enabled and inherits
the same D&D pipeline and extraction profile as production until a distinct
testing extraction policy is selected.
### Execution model
@@ -303,7 +335,10 @@ later design decision changes them:
- `/usr/local/etc/narratio` for Narratio configuration
- `/usr/local/etc/audita/config.yml` for Audita configuration
- `/usr/local/etc/notarius/config.yml` for Notarius configuration
- `/usr/local/etc/notarius/pipelines` for suite-owned imported Notarius
pipeline definitions
- `/usr/local/etc/scriptorium/config.yml` for Scriptorium configuration
- `/usr/local/etc/narratio/secrets` for future restricted credential material
- `/usr/local/share/narratio/campaigns` for version-controlled campaign data
- `/usr/local/share/narratio/prompt-library` for version-controlled prompts
and schemas
@@ -312,6 +347,8 @@ later design decision changes them:
- `/var/lib/narratio` for durable workspace and session state
- `/var/spool/narratio` for spool data
- `/var/cache/narratio` for cached data
- `/var/cache/notarius` for suite-provisioned Notarius chunk-plan and
checkpoint caches
The Narratio role creates and configures the campaign root; the pipeline role
populates it from the selected campaign source. `/usr/local/share` assumes Git
@@ -342,7 +379,7 @@ The following areas require investigation and decisions before implementation:
- The mechanism used to incorporate the independently developed pipeline role
into collection releases
- Secret injection and storage
- Suite-level operator-selection variables
- Optional suite-level operator-selection and group-membership management
- Upgrade, downgrade, and removal behavior
- Collection bootstrap and end-to-end validation details beyond the locked
dependency and testing policies above

View File

@@ -1,10 +1,10 @@
# Workspace Status
Last updated: 2026-09-11
Last updated: 2026-09-14
Current milestone: M1-03 suite-level pipeline role
Current focus: Select the next unit of work.
Current focus: Review Feature 0009 shared pipeline filesystem and execution.
| ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- |
@@ -15,7 +15,7 @@ Current focus: Select the next unit of work.
| 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 0007 is complete; select the next suite-policy feature |
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | in_progress | Review the proposed Feature 0009 shared filesystem and execution roadmap |
| 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,6 +25,8 @@ Current focus: Select the next unit of work.
| 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 | proposed | Review `docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.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` |
| 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 |