diff --git a/docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md b/docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md new file mode 100644 index 0000000..a647cbc --- /dev/null +++ b/docs/decisions/0002-shared-readable-pipeline-filesystem-policy.md @@ -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. diff --git a/docs/decisions/README.md b/docs/decisions/README.md index 13ebe65..670a275 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -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) diff --git a/docs/roadmap/features/0008-opinionated-dnd-processing-configuration.md b/docs/roadmap/features/0008-opinionated-dnd-processing-configuration.md index 6fb4d09..72e41ac 100644 --- a/docs/roadmap/features/0008-opinionated-dnd-processing-configuration.md +++ b/docs/roadmap/features/0008-opinionated-dnd-processing-configuration.md @@ -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 diff --git a/docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md b/docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md new file mode 100644 index 0000000..a2a1015 --- /dev/null +++ b/docs/roadmap/features/0009-shared-pipeline-filesystem-and-execution.md @@ -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. diff --git a/docs/roadmap/features/0010-dnd-notarius-extraction-integration.md b/docs/roadmap/features/0010-dnd-notarius-extraction-integration.md new file mode 100644 index 0000000..3f60ff3 --- /dev/null +++ b/docs/roadmap/features/0010-dnd-notarius-extraction-integration.md @@ -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.`: + +| 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. diff --git a/docs/roadmap/mvp.md b/docs/roadmap/mvp.md index cdf148d..2476db7 100644 --- a/docs/roadmap/mvp.md +++ b/docs/roadmap/mvp.md @@ -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 diff --git a/docs/status.md b/docs/status.md index 813f838..af69f42 100644 --- a/docs/status.md +++ b/docs/status.md @@ -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 |