# Feature 0007: D&D Asset Deployment and Scriptorium Integration Status: done ## Summary Extend the standalone D&D pipeline role to deploy the authoritative campaign registry and Narratio prompt library, then connect those assets to Narratio and Scriptorium through the application roles' existing public interfaces. The result is an assembled suite in which Narratio can resolve a deployed campaign and Scriptorium can discover the deployed D&D prompts and schemas. ## Problem or Opportunity Feature 0006 composes and configures all five applications, but intentionally leaves the suite's content roots empty. A consumer still has to deploy the `campaigns` and `narratio-prompts` repositories separately and override application configuration before the installed tools can find that content. Both authoritative content repositories are now present in the workspace. Their layouts make the required integration concrete: the campaign repository is already organized as Narratio's campaign registry, while the prompt repository contains top-level `prompts/` and `schemas/` trees. The prompt repository does not contain execution profiles, so this feature must not invent or configure a profile directory on its behalf. Inspection also found four stale references in the current prompt content. The character-analysis and session-recap definitions name a shared Markdown file that does not exist under that name, and the two JSON-schema prompts name schema paths that do not match the repository's `schemas/` layout. Deploying those definitions without correcting their source would leave known-broken suite content. Both campaign definitions also retain an `inputs.players_file` field that Narratio 2.0 rejects, and both `party.yml` documents use Narratio's legacy list format. Narratio's canonical party model now obtains player identity from a versioned `party_file`; the obsolete field must be removed and the party documents migrated before either deployed campaign can pass native configuration validation. ## Governing Policies - [The Ansible house style](../../ansible.md) governs the role interface, direct desired-state tasks, privilege escalation, and downstream role configuration. - [The testing house style](../../testing.md) governs focused native outcome coverage and clean repeated convergence. - [The MVP roadmap](../mvp.md) assigns campaign and prompt deployment to the pipeline role, fixes the campaign registry location, and requires the prompt library to track upstream until it publishes releases. - [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md) requires module-owned convergence without supplemental state or redundant verification. ## Scope - Add suite-owned repository URL, revision, and installation-root variables for campaign and prompt content. - Default both repositories to their authoritative Gitea origins and the `main` branch, while allowing a caller to select another branch, tag, commit, origin, or local Git fixture. - Check out the campaign repository directly at `/usr/local/share/narratio/campaigns` by default. - Check out the prompt repository directly at `/usr/local/share/narratio/prompt-library` by default. - Treat both Git checkouts as root-managed, remotely authoritative content that is updated during ordinary role convergence. - Pass the selected campaign root to the Narratio role. - Pass `/prompts` and `/schemas` to the Scriptorium role as its native prompt and schema directories. - Leave Scriptorium's profile directory unset; the prompt repository does not provide profiles. - Remove the obsolete `inputs.players_file` declaration from both campaign definitions while retaining their `party_file` inputs. - Migrate both legacy party lists to the `narratio.party.v1` document shape, preserving their supported character, player, class, and level data. - Correct the two invalid shared-content references and the two invalid schema paths in the authoritative `narratio-prompts` repository. - Align pipeline-role defaults, argument specifications, dependency metadata, README documentation, and focused integration coverage with the expanded suite contract. ## Non-goals - Defining Scriptorium execution profiles, model backends, API endpoints, or credentials. - Selecting the final D&D prompt/profile combinations used by Narratio stages and artifacts. - Defining the broader opinionated Audita, Narratio, Notarius, Seriatim, or Scriptorium processing policy; that remains a later pipeline feature. - Enabling Notarius or defining its D&D pipelines. - Managing human operators or their group membership. - Delivering secrets or environment files. - Supporting non-Git asset sources, archive downloads, local overlay trees, per-campaign selection, or merges of multiple campaign repositories. - Making managed-host edits coexist with the authoritative repositories. - Purging untracked files, maintaining asset manifests, recording deployed commits in sidecar state, or adding independent drift/integrity checks. - Adding an asset-specific release mechanism before either content repository publishes releases. - Running a real LLM request, WhisperX request, or end-to-end transcript. - Re-testing the standalone roles' installation and configuration matrices. - Incorporating the pipeline role into `rakestraw.dnd` or publishing a role or collection release. ## Target End State Applying `rakestraw.dnd_pipeline` on a supported host installs the application suite and converges two root-managed Git working trees. The campaign checkout itself is Narratio's campaign registry, so its top-level campaign directories are immediately addressable by campaign ID. The prompt-library checkout contains its native `prompts/` and `schemas/` subdirectories without copied or rearranged content. Narratio's managed pipeline configuration uses the same suite-selected campaign root that the pipeline role populates. Scriptorium's managed configuration points its `prompt_dir` and `schema_dir` fields to the corresponding subdirectories of the suite-selected prompt root. Its `profile_dir` remains omitted unless a caller or later suite-policy feature provides one. By default, each convergence fetches and reconciles the `main` branch of both content repositories. A caller that needs reproducibility can select an immutable commit through the corresponding revision variable. Ordinary Git module change detection reports content updates, and an immediate repeat with unchanged upstream state reports no changes. The corrected prompt repository is internally consistent with its installed layout: shared content files named by prompt definitions exist relative to the definitions, and schema paths resolve relative to Scriptorium's configured schema root. No compatibility links or installation-time content rewrites are needed. ## Repository Ownership - `ansible-role-dnd-pipeline` owns the suite asset variables, Git checkout tasks, application-role variable wiring, documentation, and integration coverage. It is the primary implementation repository. - `assets/narratio-prompts` owns prompt definitions and their internal content and schema references. It changes only to correct the four discovered stale references; the pipeline role does not patch content at deployment time. - `assets/campaigns` owns the campaign registry content and layout. It changes only to remove the obsolete `players_file` fields and migrate the two party documents to Narratio's current native schema; the pipeline role does not rewrite campaign content at deployment time. - `ansible-role-narratio` and `ansible-role-scriptorium` remain unchanged and are read-only authorities for their public configuration variables. - `../narratio` and `../scriptorium` remain read-only authorities for native content discovery and validation behavior. - `rakestraw-ansible` is a read-only historical reference. Its older `/usr/local/etc` asset layout and monolithic deployment tasks are not copied. - `ansible-workspace-dnd` owns this roadmap, the later staged implementation plan, the settled MVP decisions, and aggregate status. - `ansible-collection-dnd` remains unchanged until collection assembly is selected. ## Constraints and Settled Decisions - The public additions are: | Variable | Default | Purpose | | --- | --- | --- | | `dnd_pipeline_campaigns_repository_url` | `https://gitea.maximumdirect.net/eric/campaigns.git` | Authoritative campaign Git origin | | `dnd_pipeline_campaigns_revision` | `main` | Campaign branch, tag, or commit | | `dnd_pipeline_campaigns_root` | `/usr/local/share/narratio/campaigns` | Campaign checkout and Narratio registry root | | `dnd_pipeline_prompt_library_repository_url` | `https://gitea.maximumdirect.net/eric/narratio-prompts.git` | Authoritative prompt-library Git origin | | `dnd_pipeline_prompt_library_revision` | `main` | Prompt-library branch, tag, or commit | | `dnd_pipeline_prompt_library_root` | `/usr/local/share/narratio/prompt-library` | Prompt-library checkout root | - Both repositories currently have no release tags. Tracking `main` is the deliberate suite default; callers can opt into commit pinning without a separate update switch. - `ansible.builtin.git` owns checkout creation, fetch/update behavior, tracked content convergence, and change reporting. The role does not run Git commands, compare commits, or persist revision state separately. - `update: true` and `force: true` express that the configured remote revision owns tracked content. The role does not separately remove untracked files. - The role performs the privileged content operations with task-level `become: true`. - The Narratio dependency creates the campaign root as `root:narratio` mode `0755`. The pipeline role reuses that root rather than duplicating its directory task. - The pipeline role creates the prompt-library root as `root:narratio` mode `0755` before checkout. Repository files retain their Git modes and remain operator-readable; no recursive permission normalization is required. - The pipeline role passes `dnd_pipeline_campaigns_root` as `narratio_campaigns_root`, `dnd_pipeline_prompt_library_root ~ '/prompts'` as `scriptorium_prompt_dir`, and `dnd_pipeline_prompt_library_root ~ '/schemas'` as `scriptorium_schema_dir` through ordinary dependency metadata. - `scriptorium_profile_dir` is not set by this feature. The default profile IDs named by prompt definitions do not create profile definitions, and selecting usable suite profiles belongs with the later D&D application-policy work. - The prompt source corrections use the paths actually present in the repository: `../common/previous_recap.user.md`, `analyze/scene_map.schema.json`, and `trim/bounds.schema.json`. - The campaign source corrections remove `inputs.players_file` from `centaurs/campaign.yml` and `dilfs/campaign.yml`. The existing `inputs.party_file` field remains the canonical party source. - Each party document uses `schema_version: narratio.party.v1` and a `characters` map. Stable character IDs are the lowercase underscore forms of their names: `krek`, `rick_oathbreaker`, `tlann`, `torvass_oathbreaker`, `hrank_greenfield`, `alan_hohey`, `svend_balderk`, and `popov`. - Each character retains its player name, display name, class, and level in the corresponding native nested fields. Legacy `category: pc` is implicit in membership in the canonical character map. Legacy free-form notes are retained as adjacent YAML comments because `narratio.party.v1` has no note field. Popov's evident `pladin` typo is corrected to `paladin` during the otherwise mechanical migration. - The now-unused `players.yml` files are not deleted or otherwise repurposed by this feature. - The existing dependency-management switch is not expanded. With `dnd_pipeline_manage_build_dependencies: true`, the composed application roles install Git before pipeline tasks execute. A caller that disables dependency management remains responsible for providing Git as well as Go. - Repository URLs and revisions are data, not secrets. No credentials are added to role defaults or tests. ## Simplest Viable Implementation The production change should remain a small extension of the composition role: 1. Remove the obsolete `players_file` field from both campaign definitions and migrate both party documents to `narratio.party.v1`. 2. Correct the four stale paths in the prompt source repository. 3. Add and type the six asset variables. 4. Map the campaign root and prompt/schema directories into the existing Narratio and Scriptorium dependency variables. 5. Declare the prompt-library root with `ansible.builtin.file`. 6. Converge the campaign and prompt repositories with two `ansible.builtin.git` tasks. 7. Update consumer documentation and extend the existing integration driver with the asset-specific native outcomes and clean repeat. No preliminary `stat`, remote revision query, registered-result conditional, handler, checksum, manifest, or post-checkout permission sweep is required. The file and Git modules already own the selected desired states. ## Rationale and Alternatives Checking each repository out directly at its installed root preserves the upstream layout and makes updates a single module-owned operation. Copying files from a separate checkout would add a second synchronization boundary, and installing compatibility links for stale prompt references would encode source defects into deployment logic. Correcting those paths at their source is smaller and makes the asset repository useful outside this role as well. The dedicated `/usr/local/share/narratio/prompt-library` root makes the relationship clear without producing a confusing `prompts/prompts` path. Its `prompts/` and `schemas/` children map directly to Scriptorium's native configuration fields. `/usr/local/share` is appropriate for host-wide, root-managed, architecture-independent application data and is consistent with the already selected campaign location. One suite root variable per content repository keeps the Git destination and application configuration coupled. Hard-coding each path independently would permit accidental divergence, while exposing separate checkout and installed paths would add flexibility for which no consumer requirement exists. Tracking `main` matches the prompt-library policy already selected for the MVP and is also the practical campaign default while that repository has no releases. A single revision variable still permits immutable deployments. Adding an update boolean would create overlapping modes without improving that choice: selecting a commit already fixes content, and selecting a branch expresses the intent to follow it. ## Acceptance Criteria ### Required Asset Behavior - Applying the pipeline role checks out the configured campaign repository at `dnd_pipeline_campaigns_root` and the configured prompt repository at `dnd_pipeline_prompt_library_root`. - The default origins, revisions, and roots match the fixed public interface. - A caller can replace either origin, revision, or root through its suite variable without editing role tasks or dependency metadata. - Narratio's managed configuration names the exact campaign root populated by the pipeline role. - Scriptorium's managed configuration names the deployed `prompts/` and `schemas/` directories and does not acquire a profile directory from this feature. - Both deployed campaign definitions and their versioned party documents conform to Narratio 2.0's canonical party-input contract and pass native validation by campaign ID. - The two prompt definitions that use previous-recap content load the existing `previous_recap.user.md` file, and both JSON-schema definitions resolve paths beneath the configured schema directory. - The managed content roots are root-owned and operator-readable. Runtime and operator accounts do not receive write access through this feature. - Upstream changes to a selected branch are applied by a later role run; selecting an immutable commit produces stable content. - An immediate repeated role application with unchanged inputs and upstream state reports no changes. - The role contains no content copies, deployment-time prompt rewrites, redundant state probes, revision sidecars, checksums, or production self-validation. - Only `ansible-role-dnd-pipeline`, `assets/campaigns`, `assets/narratio-prompts`, and workspace planning/status documentation change. ### Required Validation - YAML syntax checking and production-profile ansible-lint pass for the role and its test playbooks. - The integration driver uses explicit repository URL and revision inputs for controlled local Git fixtures rather than depending on mutable network state. - Narratio natively validates its managed pipeline configuration with a campaign selected by ID from the deployed registry. - Scriptorium natively inspects a deployed prompt through its managed configuration, including a representative definition that uses the repaired shared-content path. - A representative JSON-schema prompt has a schema path that resolves beneath the configured deployed schema directory. - The asset-enabled baseline is followed immediately by a convergence that reports no changes. - Existing suite version-forwarding coverage remains intact; the feature does not repeat standalone application installation matrices. - Tests do not assert current default revisions as immutable facts, enumerate every asset as a snapshot, inspect Git internals, trace task execution, or re-test `ansible.builtin.file` and `ansible.builtin.git` behavior. ## Dependencies and Follow-up Work Feature 0006 and all five standalone roles are complete. The managed host must be able to reach the selected content repositories unless callers provide local origins. The narrow campaign and prompt source corrections must be committed before an integration test pins or checks out their resulting revisions. The next suite-policy feature should select actual Scriptorium profiles and backends together with Narratio prompt IDs, artifacts, and other opinionated D&D application settings. Operator access, secret delivery, end-to-end processing validation, and collection assembly also remain separate work. Before a suite or collection release, both asset repositories need an explicit release policy. If they begin publishing immutable releases, the suite should replace its branch defaults with compatible released revisions. Feature 0007 was completed by campaign commit `d1193e8`, prompt-library commit `c7e1845`, pipeline-role commits `a6ce224` and `cbfd601`, and final test-quality remediation commit `7572fa3`. The complete integration suite and post-remediation review passed with no remaining findings. ## Potential Future Hardening - Verify signed asset releases when the repositories publish them. - Protect managed checkouts against hostile repository ownership changes. - Provide a controlled offline mirror or packaged asset artifact.