Compare commits

..

14 Commits

Author SHA1 Message Date
ce5b838d95 Validate and pin the testing overlay collection dependencies 2026-09-22 18:57:15 +00:00
b6d7130046 Bundle the Notarius testing overlay 2026-09-22 18:53:13 +00:00
e1238eb4fa Squashed 'roles/pipeline/' changes from 8ceb3f4..c56a942
c56a942 Add the Notarius testing overlay and production model defaults

git-subtree-dir: roles/pipeline
git-subtree-split: c56a9425d30ef714166f1ff7675b202590f86425
2026-09-22 18:53:13 +00:00
54889e6b29 Update the bundled pipeline to Narratio v2.2.0 2026-09-22 01:57:05 +00:00
68a8bbc462 Squashed 'roles/pipeline/' changes from f48008a..8ceb3f4
8ceb3f4 Upgrade the pipeline to Narratio v2.2.0

git-subtree-dir: roles/pipeline
git-subtree-split: 8ceb3f49418d0919de642894af927e9c74334894
2026-09-22 01:57:05 +00:00
2a53979069 Update the bundled pipeline to Narratio v2.1.2 2026-09-21 13:50:39 +00:00
19b1dcabcf Squashed 'roles/pipeline/' changes from 51566af..f48008a
f48008a Upgrade the pipeline to Narratio v2.1.2

git-subtree-dir: roles/pipeline
git-subtree-split: f48008aa38e1c50adde18aa455d12a8ad77023c2
2026-09-21 13:50:39 +00:00
4691344676 Import D&D storage and publishing 2026-09-21 03:37:02 +00:00
77f67adbc0 Squashed 'roles/pipeline/' changes from c13f726..51566af
51566af Enable D&D storage and publishing

git-subtree-dir: roles/pipeline
git-subtree-split: 51566afcf69083cdbb5b5718f2544c86b079001c
2026-09-21 03:37:02 +00:00
cf3de016ee Prepare collection storage credentials 2026-09-21 03:36:30 +00:00
d292297b6a Squashed 'roles/pipeline/' changes from 78afffe..c13f726
c13f726 Add optional pipeline operator enrollment

git-subtree-dir: roles/pipeline
git-subtree-split: c13f726a0a846180a1aa95d110b8bbc801edaae5
2026-09-18 12:57:00 +00:00
c0b0ebd13e Import pipeline operator enrollment 2026-09-18 12:57:00 +00:00
f62445ad1e Squashed 'roles/pipeline/' changes from 7c2bad8..78afffe
78afffe Clarify the pipeline snapshot workflow

git-subtree-dir: roles/pipeline
git-subtree-split: 78afffe8e5fdedbd274e256dfa0e0721cfbf9a5c
2026-09-17 23:51:51 +00:00
5e695f38d0 Import pipeline documentation correction 2026-09-17 23:51:51 +00:00
12 changed files with 405 additions and 68 deletions

View File

@@ -8,6 +8,10 @@ Release `0.1.0` contains the reviewed `rakestraw.dnd_pipeline` `v0.1.0`
snapshot and pins the Seriatim, Audita, Notarius, Scriptorium, and Narratio
roles to their respective `v0.1.0` releases.
The current development snapshot advances Narratio and Notarius through public
commit pins and includes the suite's separate Notarius testing overlay. This
does not replace or modify the published `0.1.0` release artifact.
## Install release 0.1.0
Download the tagged compatibility manifest and install its exact standalone

View File

@@ -11,7 +11,7 @@ roles:
- name: rakestraw.notarius
src: https://gitea.maximumdirect.net/eric/ansible-role-notarius.git
scm: git
version: v0.1.0
version: a82a83dfc23bb80a59f45f94f78d6754c47285e7
- name: rakestraw.scriptorium
src: https://gitea.maximumdirect.net/eric/ansible-role-scriptorium.git
scm: git
@@ -19,7 +19,7 @@ roles:
- name: rakestraw.narratio
src: https://gitea.maximumdirect.net/eric/ansible-role-narratio.git
scm: git
version: v0.1.0
version: 330afe7856da94b2402a75447f4b60aba767843f
collections:
- name: ansible.posix
version: 2.2.0

View File

@@ -18,7 +18,8 @@ ansible-galaxy collection install -r collections/requirements.yml
The dependency manifest installs the roles under their canonical names:
`rakestraw.seriatim`, `rakestraw.audita`, `rakestraw.notarius`,
`rakestraw.scriptorium`, and `rakestraw.narratio`. It selects the compatible
`v0.1.0` release of each role. This standalone role is named
`v0.1.0` releases where compatible and public commit pins for Narratio and
Notarius when the suite needs newer interfaces. This standalone role is named
`rakestraw.dnd_pipeline`.
```yaml
@@ -49,8 +50,9 @@ The collection source exposes a reviewed snapshot of this role as
Collection consumers should follow the unified bootstrap instructions in the
[`rakestraw.dnd` collection repository](https://gitea.maximumdirect.net/eric/ansible-collection-dnd).
This standalone repository remains authoritative for role changes; collection
maintainers import a reviewed release as a snapshot. Collection releases are
published independently and are listed in the collection repository.
maintainers import a reviewed, pushed commit or immutable tag as a snapshot.
Collection releases are published independently and are listed in the
collection repository.
## Variables
@@ -60,8 +62,8 @@ The compatible application versions are selected through these variables:
| Variable | Default |
| --- | --- |
| `dnd_pipeline_audita_version` | `v0.9.1` |
| `dnd_pipeline_narratio_version` | `v2.1.0` |
| `dnd_pipeline_notarius_version` | `v0.7.0` |
| `dnd_pipeline_narratio_version` | `v2.2.0` |
| `dnd_pipeline_notarius_version` | `v0.7.1` |
| `dnd_pipeline_seriatim_version` | `v1.5.0` |
| `dnd_pipeline_scriptorium_version` | `v0.13.0` |
| `dnd_pipeline_manage_build_dependencies` | `true` |
@@ -89,6 +91,7 @@ group before the remaining configuration-bearing dependencies run.
| --- | --- |
| `dnd_pipeline_runtime_user` | `narratio` |
| `dnd_pipeline_runtime_group` | `narratio` |
| `dnd_pipeline_operator_users` | `[]` |
| `dnd_pipeline_config_directory_mode` | `0755` |
| `dnd_pipeline_config_file_mode` | `0644` |
@@ -144,12 +147,47 @@ run-specific output path.
| `dnd_pipeline_narratio_render_enabled` | `true` |
| `dnd_pipeline_narratio_render_format` | `markdown` |
| `dnd_pipeline_narratio_testing_scriptorium_profile` | `gemini-flash-latest` |
| `dnd_pipeline_notarius_testing_llm_profile` | `gpt-luna-latest` |
`dnd_pipeline_audita_output_schema` is also the Narratio Audita-adapter schema;
it is the shared cross-application boundary. Other Narratio-local controls,
including reports, timeouts, debug rendering, presentation, and bounds prompt
profile selection, remain Narratio defaults.
### Storage and publication policy
The suite selects Narratio's S3 backend and the established Backblaze-compatible
archive. These are ordinary inventory variables, so deployments may replace
the selected policy through the role's public interface.
| Variable | Default policy |
| --- | --- |
| `dnd_pipeline_narratio_workspace_cleanup_after_publish` | `true` |
| `dnd_pipeline_narratio_storage_backend` | `s3` |
| `dnd_pipeline_narratio_storage_s3_bucket` | `rakestraw-assets` |
| `dnd_pipeline_narratio_storage_s3_root_prefix` | `dnd` |
| `dnd_pipeline_narratio_storage_s3_region` | `us-east-1` |
| `dnd_pipeline_narratio_storage_s3_endpoint` | `https://s3.us-east-005.backblazeb2.com` |
| `dnd_pipeline_narratio_storage_s3_force_path_style` | `true` |
| `dnd_pipeline_narratio_storage_s3_access_key_id` | `OBJECT_STORAGE_KEY_ID` |
| `dnd_pipeline_narratio_storage_s3_secret_access_key` | `OBJECT_STORAGE_KEY` |
| `dnd_pipeline_narratio_cache_s3_audio` | `true` |
| `dnd_pipeline_narratio_publish_enabled` | `true` |
| `dnd_pipeline_narratio_publish_upload_run` | `true` |
`dnd_pipeline_narratio_publish_outputs` is a complete native list, not a list
merged with the suite default. It publishes final and trimmed JSON, final and
trimmed Markdown, session recap, hostile rumors, and optional deranged rumors.
Every rule omits `dest`: Narratio derives transcript destinations from its
built-in sources and artifact destinations from the configured artifact output
paths.
S3 session audio uses the maximum available native cache beneath
`/var/cache/narratio`. After successful run publication, Narratio cleans the
published workspace target while preserving that cache. The suite deliberately
does not set `narratio_spool_delete_audio_after_publish`; spool-audio retention
continues to use Narratio's application default.
### Artifacts and profiles
The role owns these complete native mapping variables. Replacing one mapping
@@ -186,14 +224,25 @@ suite-owned base fragments in this fixed order:
└── profiles/testing.yml
```
The `testing` profile is an overlay, not a second configuration tree. It only
sets the Scriptorium `profile_id` for the four artifact sources and the one
family. Its default, `gemini-flash-latest`, is an inexpensive development
Notarius follows the corresponding base-and-overlay layout:
```text
/usr/local/etc/notarius/
├── config.yml
├── pipelines/dnd-session.yml
└── profiles/testing.yml
```
The `testing` profile is an overlay, not a second configuration tree. It sets
the Scriptorium `profile_id` for the four artifact sources and the one family,
and explicitly selects Notarius's separately managed `testing` overlay. The
Scriptorium default, `gemini-flash-latest`, is an inexpensive development
choice, not a compatibility guarantee. Replace it through inventory when a
different testing profile is appropriate:
```yaml
dnd_pipeline_narratio_testing_scriptorium_profile: endpoint-profile
dnd_pipeline_notarius_testing_llm_profile: alternate-economy-profile
```
### Notarius extraction policy
@@ -201,6 +250,8 @@ dnd_pipeline_narratio_testing_scriptorium_profile: endpoint-profile
The Notarius root configuration imports the fixed
`pipelines/dnd-session.yml` fragment. The suite owns that fragment at
`/usr/local/etc/notarius/pipelines/dnd-session.yml`; callers do not edit it.
The separate `/usr/local/etc/notarius/profiles/testing.yml` overlay changes only
the selected suite pipeline's LLM profile.
| Variable | Default policy |
| --- | --- |
@@ -208,6 +259,7 @@ The Notarius root configuration imports the fixed
| `dnd_pipeline_notarius_cache_root` | `/var/cache/notarius` |
| `dnd_pipeline_notarius_cache_chunk_plans_mode` | `auto` |
| `dnd_pipeline_notarius_cache_checkpoints_enabled` | `true` |
| `dnd_pipeline_notarius_testing_llm_profile` | `gpt-luna-latest` |
| `dnd_pipeline_narratio_notarius_pipeline_id` | `dnd-session` |
| `dnd_pipeline_narratio_notarius_llm_api_key` | `OPENROUTER_API_KEY` |
| `dnd_pipeline_narratio_notarius_resume` | `true` |
@@ -216,7 +268,11 @@ The Notarius root configuration imports the fixed
The pipeline, reference, and output values are complete native mappings.
Inventory can replace them or compose additions with Jinja's `combine` filter;
a replacement pipeline map requires a matching selected pipeline ID.
a replacement pipeline map requires a matching selected pipeline ID. The base
`dnd-session` pipeline selects `gpt-terra-latest`, while the testing overlay
selects `gpt-luna-latest`. Both are moving catalog IDs rather than immutable
model promises. Pipeline and binding-level overrides retain Notarius's native
precedence; the suite does not rewrite caller-supplied bindings.
Narratio materializes the `party`, `players`, and `glossary` references for each
invocation. No campaign filesystem path appears in Notarius configuration. The
@@ -225,16 +281,22 @@ that input. The accepted sources are
`narratio.extraction.item_registry`, `npc_registry`, `location_registry`,
`scene_descriptions`, `item_occurrences`, `spells`, `combat_turns`,
`npc_occurrences`, `location_occurrences`, and `enemy_events`.
They remain available as `narratio.extraction.<output_key>` inputs for future
analyze artifacts whether or not a source has a stable publication rule;
accepted extraction and published output selection are independent interfaces.
Narratio forwards the typed `OPENROUTER_API_KEY` reference to the selected
Notarius profile and ordinary extraction requests checkpoint reuse with
`resume: true`. Chunk plans use Notarius's root-owned `auto` policy; the
pipeline deliberately leaves Narratio's optional `chunk_cache` override unset.
The `chunk-plans` and `checkpoints` paths derive from the cache root and are
created by Notarius during use. Base and `testing` configurations select the
same `dnd-extraction` profile and Notarius pipeline; the testing overlay changes
only Scriptorium profiles, so a real testing run may invoke Notarius. The
integration suite performs offline configuration inspection only.
created by Notarius during use. Notarius v0.7.1 selects PromptKit v0.10.0 and
OpenRouter catalog v2.20260922.1, which supplies both suite-selected IDs.
Existing checkpoints with the previous profile-source identity are not reused;
source-keyed chunk plans and output artifacts remain compatible. No cache
deletion or forced extraction is performed by this role. A real testing run may
invoke Notarius; the integration suite performs offline configuration inspection
only and makes no provider request.
### Inspecting configuration
@@ -258,8 +320,15 @@ inspection shows enabled sources, inferred dependencies, and generated family
members; the diff shows the overlay's profile selections without modifying
managed files.
Storage and publishing, operator selection and group-membership management,
scheduling, and end-to-end external execution remain deferred.
With valid object-storage credentials, the selected policy enables Narratio's
native [S3 session-audio](https://gitea.maximumdirect.net/eric/narratio/src/tag/v2.1.1/docs/config.md#session),
[publication](https://gitea.maximumdirect.net/eric/narratio/src/tag/v2.1.1/docs/operations.md#publish-workflow),
[restore](https://gitea.maximumdirect.net/eric/narratio/src/tag/v2.1.1/docs/operations.md#restore-workflow),
[publication locks](https://gitea.maximumdirect.net/eric/narratio/src/tag/v2.1.1/docs/operations.md#publish-locks),
[session status](https://gitea.maximumdirect.net/eric/narratio/src/tag/v2.1.1/docs/operations.md#standard-session-workflow),
and [cleanup](https://gitea.maximumdirect.net/eric/narratio/src/tag/v2.1.1/docs/operations.md#cleanup)
workflows. These remain application commands and lifecycle rules; scheduling
and real end-to-end execution remain deployment concerns.
### Shared execution filesystem
@@ -268,27 +337,30 @@ scheduling, and end-to-end external execution remain deferred.
`narratio:narratio` mode `2775` **setgid** directories. Their access and
default ACLs retain owner and group write access plus world read/traverse access
for newly created content. The pipeline may run as `narratio` or as a human
account already in the selected runtime group; the production role neither
selects people nor manages their group membership. For example, a consumer
play can manage its selected operator separately:
account in the selected runtime group. Consumers can enroll selected existing
human accounts through the role interface:
```yaml
- name: Add the selected operator to the pipeline group
become: true
ansible.builtin.user:
name: "{{ pipeline_operator }}"
groups:
- "{{ dnd_pipeline_runtime_group }}"
append: true
dnd_pipeline_operator_users:
- eric
- alice
```
Every selected account must already exist; the role does not create human
accounts or manage their identity and login policy. Enrollment adds the
selected runtime group without replacing other supplementary groups. Removing
or omitting a name later does not revoke membership. A newly enrolled operator
must begin a new login session before the operating system exposes the added
supplementary group to that session.
Configuration, transcripts, caches, generated artifacts, campaign data,
prompts, and logs are non-secret D&D content. Credentials use the restricted
`/usr/local/etc/narratio/secrets` subtree, owned by the selected runtime user
and group with mode `0750`; managed files use mode `0640`. Runtime-group
membership authorizes use of these shared credentials, while the subtree grants
no world access. Ordinary configuration remains world-readable and contains
only reference names.
membership, including enrollment through `dnd_pipeline_operator_users`,
authorizes use of these shared credentials, while the subtree grants no world
access. Ordinary configuration remains world-readable and contains only
reference names.
### Managed credentials
@@ -306,8 +378,17 @@ consumer workflow, not role functionality:
dnd_pipeline_secrets:
AUDITA_LLM_API_KEY: "{{ vault_dnd_audita_llm_api_key }}"
OPENROUTER_API_KEY: "{{ vault_dnd_openrouter_api_key }}"
OBJECT_STORAGE_KEY_ID: "{{ vault_dnd_object_storage_key_id }}"
OBJECT_STORAGE_KEY: "{{ vault_dnd_object_storage_key }}"
```
Only the reference names enter ordinary Narratio configuration; credential
values remain in encrypted inventory and the restricted managed secrets
directory. A deployment using Narratio's ambient AWS SDK provider chain can
set both `dnd_pipeline_narratio_storage_s3_access_key_id` and
`dnd_pipeline_narratio_storage_s3_secret_access_key` to `null`. The pair must
be omitted together.
Scriptorium profiles continue to own their `api_key_env` selection. To supply
that credential through the suite, add a `dnd_pipeline_secrets` entry whose
name matches the selected profile's `api_key_env`. Narratio's secrets bootstrap

View File

@@ -1,7 +1,7 @@
---
dnd_pipeline_audita_version: v0.9.1
dnd_pipeline_narratio_version: v2.1.0
dnd_pipeline_notarius_version: v0.7.0
dnd_pipeline_narratio_version: v2.2.0
dnd_pipeline_notarius_version: v0.7.1
dnd_pipeline_seriatim_version: v1.5.0
dnd_pipeline_scriptorium_version: v0.13.0
dnd_pipeline_manage_build_dependencies: true
@@ -9,6 +9,7 @@ dnd_pipeline_go_snap_channel: 1.26/stable
dnd_pipeline_go_binary: /snap/bin/go
dnd_pipeline_runtime_user: narratio
dnd_pipeline_runtime_group: narratio
dnd_pipeline_operator_users: []
dnd_pipeline_secrets: {}
dnd_pipeline_config_directory_mode: "0755"
dnd_pipeline_config_file_mode: "0644"
@@ -57,7 +58,7 @@ dnd_pipeline_audita_diagnostics_work_dir: /tmp/audita
dnd_pipeline_audita_diagnostics_retention: auto
dnd_pipeline_notarius_pipelines:
dnd-session:
llm_profile: dnd-extraction
llm_profile: gpt-terra-latest
input:
module: seriatim
chunk:
@@ -206,6 +207,34 @@ dnd_pipeline_notarius_pipelines:
dnd_pipeline_notarius_cache_root: /var/cache/notarius
dnd_pipeline_notarius_cache_chunk_plans_mode: auto
dnd_pipeline_notarius_cache_checkpoints_enabled: true
dnd_pipeline_notarius_testing_llm_profile: gpt-luna-latest
dnd_pipeline_narratio_workspace_cleanup_after_publish: true
dnd_pipeline_narratio_storage_backend: s3
dnd_pipeline_narratio_storage_s3_bucket: rakestraw-assets
dnd_pipeline_narratio_storage_s3_root_prefix: dnd
dnd_pipeline_narratio_storage_s3_region: us-east-1
dnd_pipeline_narratio_storage_s3_endpoint: https://s3.us-east-005.backblazeb2.com
dnd_pipeline_narratio_storage_s3_force_path_style: true
dnd_pipeline_narratio_storage_s3_access_key_id: OBJECT_STORAGE_KEY_ID
dnd_pipeline_narratio_storage_s3_secret_access_key: OBJECT_STORAGE_KEY
dnd_pipeline_narratio_cache_s3_audio: true
dnd_pipeline_narratio_publish_enabled: true
dnd_pipeline_narratio_publish_upload_run: true
dnd_pipeline_narratio_publish_outputs:
- source: narratio.transcript.final
required: true
- source: narratio.transcript.final_trimmed
required: true
- source: narratio.transcript.final_markdown
required: true
- source: narratio.transcript.final_trimmed_markdown
required: true
- source: narratio.artifact.session_recap
required: true
- source: narratio.artifact.hostile_rumors
required: true
- source: narratio.artifact.deranged_rumors
required: false
dnd_pipeline_narratio_seriatim_output_schema: seriatim-intermediate
dnd_pipeline_narratio_normalize_output_path: transcripts/final.json
dnd_pipeline_narratio_normalize_output_schema: seriatim-intermediate

View File

@@ -43,6 +43,11 @@ argument_specs:
type: str
required: true
description: Shared group for suite-managed configuration.
dnd_pipeline_operator_users:
type: list
elements: str
required: true
description: Existing human accounts enrolled in the shared runtime group.
dnd_pipeline_secrets:
type: dict
required: true
@@ -216,6 +221,62 @@ argument_specs:
type: bool
required: true
description: Whether Notarius records checkpoints.
dnd_pipeline_notarius_testing_llm_profile:
type: str
required: true
description: Notarius LLM profile selected by the testing overlay.
dnd_pipeline_narratio_workspace_cleanup_after_publish:
type: bool
required: true
description: Whether Narratio cleans successfully published workspace state.
dnd_pipeline_narratio_storage_backend:
type: str
required: true
description: Narratio object-storage backend.
dnd_pipeline_narratio_storage_s3_bucket:
type: str
required: false
description: S3 bucket used by Narratio.
dnd_pipeline_narratio_storage_s3_root_prefix:
type: str
required: false
description: Root prefix for Narratio objects in the S3 bucket.
dnd_pipeline_narratio_storage_s3_region:
type: str
required: false
description: S3 region used by Narratio.
dnd_pipeline_narratio_storage_s3_endpoint:
type: str
required: false
description: S3-compatible endpoint used by Narratio.
dnd_pipeline_narratio_storage_s3_force_path_style:
type: bool
required: false
description: Whether Narratio uses path-style S3 requests.
dnd_pipeline_narratio_storage_s3_access_key_id:
type: str
required: false
description: Nullable access-key environment-variable reference.
dnd_pipeline_narratio_storage_s3_secret_access_key:
type: str
required: false
description: Nullable secret-key environment-variable reference.
dnd_pipeline_narratio_cache_s3_audio:
type: bool
required: true
description: Whether Narratio caches downloaded S3 audio.
dnd_pipeline_narratio_publish_enabled:
type: bool
required: true
description: Whether Narratio publication is enabled.
dnd_pipeline_narratio_publish_upload_run:
type: bool
required: true
description: Whether Narratio uploads immutable run content.
dnd_pipeline_narratio_publish_outputs:
type: list
required: true
description: Complete native list of Narratio output publication rules.
dnd_pipeline_narratio_seriatim_output_schema:
type: str
required: true

View File

@@ -39,6 +39,19 @@ dependencies:
- path: artifacts/deranged-rumors.yml
- path: artifacts/scene-map.yml
- path: artifact-families/character-meta-analysis.yml
narratio_workspace_cleanup_after_publish: "{{ dnd_pipeline_narratio_workspace_cleanup_after_publish }}"
narratio_storage_backend: "{{ dnd_pipeline_narratio_storage_backend }}"
narratio_storage_s3_bucket: "{{ dnd_pipeline_narratio_storage_s3_bucket }}"
narratio_storage_s3_root_prefix: "{{ dnd_pipeline_narratio_storage_s3_root_prefix }}"
narratio_storage_s3_region: "{{ dnd_pipeline_narratio_storage_s3_region }}"
narratio_storage_s3_endpoint: "{{ dnd_pipeline_narratio_storage_s3_endpoint }}"
narratio_storage_s3_force_path_style: "{{ dnd_pipeline_narratio_storage_s3_force_path_style }}"
narratio_storage_s3_access_key_id: "{{ dnd_pipeline_narratio_storage_s3_access_key_id }}"
narratio_storage_s3_secret_access_key: "{{ dnd_pipeline_narratio_storage_s3_secret_access_key }}"
narratio_cache_s3_audio: "{{ dnd_pipeline_narratio_cache_s3_audio }}"
narratio_publish_enabled: "{{ dnd_pipeline_narratio_publish_enabled }}"
narratio_publish_upload_run: "{{ dnd_pipeline_narratio_publish_upload_run }}"
narratio_publish_outputs: "{{ dnd_pipeline_narratio_publish_outputs }}"
narratio_seriatim_binary: /usr/local/bin/seriatim
narratio_audita_binary: /usr/local/bin/audita
narratio_audita_config_path: /usr/local/etc/audita/config.yml

View File

@@ -11,7 +11,7 @@ roles:
- name: rakestraw.notarius
src: https://gitea.maximumdirect.net/eric/ansible-role-notarius.git
scm: git
version: v0.1.0
version: a82a83dfc23bb80a59f45f94f78d6754c47285e7
- name: rakestraw.scriptorium
src: https://gitea.maximumdirect.net/eric/ansible-role-scriptorium.git
scm: git
@@ -19,4 +19,4 @@ roles:
- name: rakestraw.narratio
src: https://gitea.maximumdirect.net/eric/ansible-role-narratio.git
scm: git
version: v0.1.0
version: 330afe7856da94b2402a75447f4b60aba767843f

View File

@@ -1,4 +1,19 @@
---
- name: Validate selected pipeline operator accounts
ansible.builtin.getent:
database: passwd
key: "{{ item }}"
loop: "{{ dnd_pipeline_operator_users }}"
- name: Enroll selected pipeline operators
become: true
ansible.builtin.user:
name: "{{ item }}"
groups: "{{ dnd_pipeline_runtime_group }}"
append: true
state: present
loop: "{{ dnd_pipeline_operator_users }}"
- name: Install ACL support
become: true
ansible.builtin.apt:
@@ -131,14 +146,17 @@
- artifact-families
- profiles
- name: Create the Notarius pipeline configuration directory
- name: Create Notarius configuration directories
become: true
ansible.builtin.file:
path: /usr/local/etc/notarius/pipelines
path: "/usr/local/etc/notarius/{{ item }}"
state: directory
owner: "{{ dnd_pipeline_runtime_user }}"
group: "{{ dnd_pipeline_runtime_group }}"
mode: "{{ dnd_pipeline_config_directory_mode }}"
loop:
- pipelines
- profiles
- name: Deploy the Notarius D&D pipeline configuration
become: true
@@ -149,6 +167,15 @@
group: "{{ dnd_pipeline_runtime_group }}"
mode: "{{ dnd_pipeline_config_file_mode }}"
- name: Deploy the Notarius testing overlay
become: true
ansible.builtin.template:
src: notarius-testing.yml.j2
dest: /usr/local/etc/notarius/profiles/testing.yml
owner: "{{ dnd_pipeline_runtime_user }}"
group: "{{ dnd_pipeline_runtime_group }}"
mode: "{{ dnd_pipeline_config_file_mode }}"
- name: Deploy Narratio D&D configuration fragments
become: true
ansible.builtin.template:

View File

@@ -0,0 +1,3 @@
pipelines:
{{ dnd_pipeline_narratio_notarius_pipeline_id | to_json }}:
llm_profile: {{ dnd_pipeline_notarius_testing_llm_profile | to_json }}

View File

@@ -1,3 +1,5 @@
notarius:
config_profile: testing
scriptorium:
artifacts:
session_recap:

View File

@@ -24,6 +24,8 @@ service_fixture_file="$shared_fixture_root/service.txt"
operator_fixture_file="$shared_fixture_root/operator.txt"
synthetic_audita_api_key='audita-pipeline-synthetic-value'
synthetic_notarius_api_key='notarius-pipeline-synthetic-value'
synthetic_object_storage_key_id='object-storage-key-id-pipeline-synthetic-value'
synthetic_object_storage_key='object-storage-key-pipeline-synthetic-value'
baseline_args=(
-e 'dnd_pipeline_whisperx_transcribe_url=http://127.0.0.1:8000/transcribe'
-e "dnd_pipeline_campaigns_repository_url=file://$campaigns_repository"
@@ -31,15 +33,27 @@ baseline_args=(
-e "dnd_pipeline_prompt_library_repository_url=file://$prompt_library_repository"
-e "dnd_pipeline_prompt_library_revision=$prompt_library_revision"
-e "dnd_pipeline_prompt_library_root=$prompt_library_root"
-e "{\"dnd_pipeline_secrets\":{\"AUDITA_LLM_API_KEY\":\"$synthetic_audita_api_key\",\"OPENROUTER_API_KEY\":\"$synthetic_notarius_api_key\"}}"
-e "{\"dnd_pipeline_operator_users\":[\"$operator_user\"]}"
-e "{\"dnd_pipeline_secrets\":{\"AUDITA_LLM_API_KEY\":\"$synthetic_audita_api_key\",\"OPENROUTER_API_KEY\":\"$synthetic_notarius_api_key\",\"OBJECT_STORAGE_KEY_ID\":\"$synthetic_object_storage_key_id\",\"OBJECT_STORAGE_KEY\":\"$synthetic_object_storage_key\"}}"
-e 'dnd_pipeline_narratio_storage_backend=s3'
-e 'dnd_pipeline_narratio_storage_s3_bucket=dnd-pipeline-fixture'
-e 'dnd_pipeline_narratio_storage_s3_root_prefix=fixture/dnd'
-e 'dnd_pipeline_narratio_storage_s3_region=fixture-1'
-e 'dnd_pipeline_narratio_storage_s3_endpoint=https://storage.fixture.invalid'
-e 'dnd_pipeline_narratio_storage_s3_access_key_id=OBJECT_STORAGE_KEY_ID'
-e 'dnd_pipeline_narratio_storage_s3_secret_access_key=OBJECT_STORAGE_KEY'
-e '{"dnd_pipeline_narratio_workspace_cleanup_after_publish":false,"dnd_pipeline_narratio_storage_s3_force_path_style":false,"dnd_pipeline_narratio_cache_s3_audio":false,"dnd_pipeline_narratio_publish_enabled":true,"dnd_pipeline_narratio_publish_upload_run":true}'
-e '{"dnd_pipeline_narratio_publish_outputs":[{"source":"narratio.transcript.final","required":true},{"source":"narratio.artifact.session_recap","required":true}]}'
-e 'dnd_pipeline_narratio_testing_scriptorium_profile=endpoint-profile'
-e 'dnd_pipeline_notarius_testing_llm_profile=gpt-terra-latest'
)
cleanup() {
exit_status=$?
trap - EXIT
/usr/bin/sudo /bin/rm -rf -- "$shared_fixture_root" || true
/usr/bin/sudo /usr/sbin/userdel --remove "$operator_user" 2>/dev/null || true
"$ansible_playbook" -i "$inventory" "${baseline_args[@]}" "$converge" >/dev/null 2>&1 || true
/usr/bin/sudo /usr/sbin/userdel --remove "$operator_user" 2>/dev/null || true
rm -rf -- "$test_tmp"
exit "$exit_status"
}
@@ -53,6 +67,7 @@ run_converge() {
output_file=$1
shift
env -u AUDITA_LLM_API_KEY -u OPENROUTER_API_KEY \
-u OBJECT_STORAGE_KEY_ID -u OBJECT_STORAGE_KEY \
"$ansible_playbook" -i "$inventory" "$@" "$converge" | tee "$output_file"
}
@@ -70,6 +85,7 @@ printf '%s\n' \
-p "$test_tmp/roles"
"$ansible_playbook" -i "$inventory" --syntax-check "$converge"
"$workspace_venv/bin/ansible-lint" --offline --profile production "$converge"
/usr/bin/sudo /usr/sbin/useradd --create-home --shell /usr/sbin/nologin "$operator_user"
baseline_log="$test_tmp/baseline.log"
run_converge "$baseline_log" "${baseline_args[@]}"
@@ -77,9 +93,14 @@ run_converge "$baseline_log" "${baseline_args[@]}"
/usr/local/bin/audita config validate --config /usr/local/etc/audita/config.yml
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml \
--pipeline dnd-session
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml \
--config-profile testing --pipeline dnd-session
notarius_effective_config="$test_tmp/notarius-effective.yml"
/usr/local/bin/notarius config effective --config /usr/local/etc/notarius/config.yml \
> "$notarius_effective_config"
notarius_testing_effective_config="$test_tmp/notarius-testing-effective.yml"
/usr/local/bin/notarius config effective --config /usr/local/etc/notarius/config.yml \
--config-profile testing > "$notarius_testing_effective_config"
grep -Fq 'mode: auto' "$notarius_effective_config"
grep -Fq 'step: describe-session' "$notarius_effective_config"
/usr/local/bin/scriptorium inspect profile --config /usr/local/etc/scriptorium/config.yml \
@@ -94,6 +115,10 @@ narratio_effective_config="$test_tmp/narratio-effective.yml"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config show \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs \
> "$narratio_effective_config"
narratio_testing_effective_config="$test_tmp/narratio-testing-effective.yml"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config show \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs --profile testing \
> "$narratio_testing_effective_config"
grep -Fq 'enabled: true' "$narratio_effective_config"
grep -Fq 'llm_api_key: AUDITA_LLM_API_KEY' "$narratio_effective_config"
grep -Fq 'pipeline_id: dnd-session' "$narratio_effective_config"
@@ -102,8 +127,62 @@ grep -Fq 'resume: true' "$narratio_effective_config"
! grep -Fq 'chunk_cache:' "$narratio_effective_config"
grep -Fq 'party: narratio.input.party' "$narratio_effective_config"
grep -Fq 'lane_id: item-registry' "$narratio_effective_config"
! grep -Fq "$synthetic_audita_api_key" "$baseline_log" "$narratio_effective_config" "$notarius_effective_config"
! grep -Fq "$synthetic_notarius_api_key" "$baseline_log" "$narratio_effective_config" "$notarius_effective_config"
"$workspace_venv/bin/python" - \
"$narratio_effective_config" "$narratio_testing_effective_config" <<'PY'
import sys
import yaml
with open(sys.argv[1], encoding="utf-8") as config_file:
config = yaml.safe_load(config_file)
with open(sys.argv[2], encoding="utf-8") as config_file:
testing_config = yaml.safe_load(config_file)
assert config["workspace"]["cleanup_after_publish"] is False
assert config["storage"] == {
"backend": "s3",
"s3": {
"bucket": "dnd-pipeline-fixture",
"root_prefix": "fixture/dnd",
"region": "fixture-1",
"endpoint": "https://storage.fixture.invalid",
"force_path_style": False,
"access_key_id": "OBJECT_STORAGE_KEY_ID",
"secret_access_key": "OBJECT_STORAGE_KEY",
},
}
assert config["cache"]["s3_audio"] is False
assert config["publish"] == {
"enabled": True,
"upload_run": True,
"outputs": [
{
"source": "narratio.transcript.final",
"dest": "transcripts/final.json",
"required": True,
},
{
"source": "narratio.artifact.session_recap",
"dest": "artifacts/session_recap.md",
"required": True,
},
],
}
assert "config_profile" not in config["notarius"]
assert testing_config["notarius"]["config_profile"] == "testing"
assert all(
artifact["profile_id"] == "endpoint-profile"
for artifact in testing_config["scriptorium"]["artifacts"].values()
)
assert any(
artifact_id.startswith("character_meta_analysis_")
for artifact_id in testing_config["scriptorium"]["artifacts"]
)
PY
! grep -Fq "$synthetic_audita_api_key" "$baseline_log" "$narratio_effective_config" "$narratio_testing_effective_config" "$notarius_effective_config" "$notarius_testing_effective_config"
! grep -Fq "$synthetic_notarius_api_key" "$baseline_log" "$narratio_effective_config" "$narratio_testing_effective_config" "$notarius_effective_config" "$notarius_testing_effective_config"
! grep -Fq "$synthetic_object_storage_key_id" "$baseline_log" "$narratio_effective_config" "$narratio_testing_effective_config" "$notarius_effective_config" "$notarius_testing_effective_config"
! grep -Fq "$synthetic_object_storage_key" "$baseline_log" "$narratio_effective_config" "$narratio_testing_effective_config" "$notarius_effective_config" "$notarius_testing_effective_config"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config artifacts \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | \
awk -F '\t' '$1 == "session_recap" && $4 == "true" { found = 1 } END { exit !found }'
@@ -113,11 +192,6 @@ grep -Fq 'lane_id: item-registry' "$narratio_effective_config"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config artifacts \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | \
awk -F '\t' 'index($1, "character_meta_analysis_") == 1 && $4 == "false" && $7 == "character_meta_analysis" { found = 1 } END { exit !found }'
/usr/bin/sudo -u narratio /usr/local/bin/narratio config diff default testing \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | \
awk -F '\t' '$1 != "changed" || $2 !~ /\.profile_id$/ { invalid = 1 } END { exit invalid || NR == 0 }'
/usr/bin/sudo /usr/sbin/useradd --create-home --groups narratio \
--shell /usr/sbin/nologin "$operator_user"
/usr/bin/sudo -u "$operator_user" /usr/local/bin/narratio config validate \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs
/usr/bin/sudo -u "$operator_user" /usr/local/bin/notarius config validate \
@@ -165,21 +239,6 @@ if run_converge "$invalid_key_log" "${baseline_args[@]}" \
exit 1
fi
testing_profile_log="$test_tmp/testing-profile.log"
run_converge "$testing_profile_log" "${baseline_args[@]}" \
-e 'dnd_pipeline_narratio_testing_scriptorium_profile=endpoint-profile'
/usr/bin/sudo -u narratio /usr/local/bin/narratio config validate \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs --profile testing
/usr/bin/sudo -u narratio /usr/local/bin/narratio config diff default testing \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs | \
grep -F '"endpoint-profile"'
/usr/local/bin/scriptorium inspect profile --config /usr/local/etc/scriptorium/config.yml \
--profile-dir "$profile_dir" --profile endpoint-profile
testing_profile_repeat_log="$test_tmp/testing-profile-repeat.log"
run_converge "$testing_profile_repeat_log" "${baseline_args[@]}" \
-e 'dnd_pipeline_narratio_testing_scriptorium_profile=endpoint-profile'
require_clean_recap "$testing_profile_repeat_log"
selected_version_log="$test_tmp/selected-version.log"
run_converge "$selected_version_log" "${baseline_args[@]}" \
-e 'dnd_pipeline_seriatim_version=v1.4.0'
@@ -189,24 +248,55 @@ run_converge "$selected_version_repeat_log" "${baseline_args[@]}" \
-e 'dnd_pipeline_seriatim_version=v1.4.0'
require_clean_recap "$selected_version_repeat_log"
pipeline_group_one='{"archive-session":{"llm_profile":"dnd-extraction","input":{"module":"seriatim"},"artifacts":{"spells":{"extract":{"module":"dnd/spells"},"normalize":{"module":"dnd/spells"}}}}}'
pipeline_group_two='{"research-session":{"llm_profile":"dnd-extraction","input":{"module":"seriatim"},"artifacts":{"spells":{"extract":{"module":"dnd/spells"},"normalize":{"module":"dnd/spells"}}}}}'
alternate_config="{\"notarius_pipeline_group_one\":$pipeline_group_one,\"notarius_pipeline_group_two\":$pipeline_group_two,\"dnd_pipeline_notarius_pipelines\":\"{{ notarius_pipeline_group_one | combine(notarius_pipeline_group_two) }}\",\"dnd_pipeline_narratio_notarius_pipeline_id\":\"archive-session\",\"dnd_pipeline_notarius_cache_chunk_plans_mode\":\"bypass\"}"
pipeline_group_one='{"archive-session":{"llm_profile":"gpt-luna-latest","input":{"module":"seriatim"},"artifacts":{"spells":{"extract":{"module":"dnd/spells"},"normalize":{"module":"dnd/spells"}}}}}'
pipeline_group_two='{"research-session":{"llm_profile":"gpt-luna-latest","input":{"module":"seriatim"},"artifacts":{"spells":{"extract":{"module":"dnd/spells"},"normalize":{"module":"dnd/spells"}}}}}'
alternate_config="{\"notarius_pipeline_group_one\":$pipeline_group_one,\"notarius_pipeline_group_two\":$pipeline_group_two,\"dnd_pipeline_notarius_pipelines\":\"{{ notarius_pipeline_group_one | combine(notarius_pipeline_group_two) }}\",\"dnd_pipeline_narratio_notarius_pipeline_id\":\"archive-session\",\"dnd_pipeline_notarius_testing_llm_profile\":\"gpt-terra-latest\",\"dnd_pipeline_notarius_cache_chunk_plans_mode\":\"bypass\"}"
alternate_log="$test_tmp/alternate.log"
run_converge "$alternate_log" "${baseline_args[@]}" -e "$alternate_config"
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml \
--pipeline archive-session
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml \
--config-profile testing --pipeline archive-session
alternate_narratio_config="$test_tmp/alternate-narratio.yml"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config show \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs \
> "$alternate_narratio_config"
grep -Fq 'pipeline_id: archive-session' "$alternate_narratio_config"
alternate_testing_narratio_config="$test_tmp/alternate-testing-narratio.yml"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config show \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs --profile testing \
> "$alternate_testing_narratio_config"
alternate_effective_config="$test_tmp/alternate-effective.yml"
/usr/local/bin/notarius config effective --config /usr/local/etc/notarius/config.yml \
> "$alternate_effective_config"
grep -Fq 'archive-session:' "$alternate_effective_config"
grep -Fq 'research-session:' "$alternate_effective_config"
grep -Fq 'mode: bypass' "$alternate_effective_config"
alternate_testing_effective_config="$test_tmp/alternate-testing-effective.yml"
/usr/local/bin/notarius config effective --config /usr/local/etc/notarius/config.yml \
--config-profile testing > "$alternate_testing_effective_config"
"$workspace_venv/bin/python" - \
"$alternate_narratio_config" "$alternate_testing_narratio_config" \
"$alternate_effective_config" "$alternate_testing_effective_config" <<'PY'
import sys
import yaml
with open(sys.argv[1], encoding="utf-8") as config_file:
narratio_base = yaml.safe_load(config_file)
with open(sys.argv[2], encoding="utf-8") as config_file:
narratio_testing = yaml.safe_load(config_file)
with open(sys.argv[3], encoding="utf-8") as config_file:
notarius_base = yaml.safe_load(config_file)
with open(sys.argv[4], encoding="utf-8") as config_file:
notarius_testing = yaml.safe_load(config_file)
assert narratio_base["notarius"]["pipeline_id"] == "archive-session"
assert "config_profile" not in narratio_base["notarius"]
assert narratio_testing["notarius"]["pipeline_id"] == "archive-session"
assert narratio_testing["notarius"]["config_profile"] == "testing"
assert notarius_base["pipelines"]["archive-session"]["llm_profile"] == "gpt-luna-latest"
assert notarius_testing["pipelines"]["archive-session"]["llm_profile"] == "gpt-terra-latest"
assert notarius_testing["pipelines"]["research-session"]["llm_profile"] == "gpt-luna-latest"
assert notarius_base["cache"]["chunk_plans"]["mode"] == "bypass"
PY
alternate_repeat_log="$test_tmp/alternate-repeat.log"
run_converge "$alternate_repeat_log" "${baseline_args[@]}" -e "$alternate_config"
require_clean_recap "$alternate_repeat_log"

View File

@@ -22,7 +22,8 @@ baseline_args=(
-e "dnd_pipeline_campaigns_revision=$campaigns_revision"
-e "dnd_pipeline_prompt_library_repository_url=file://$prompt_library_repository"
-e "dnd_pipeline_prompt_library_revision=$prompt_library_revision"
-e '{"dnd_pipeline_secrets":{"AUDITA_LLM_API_KEY":"audita-pipeline-synthetic-value","OPENROUTER_API_KEY":"notarius-pipeline-synthetic-value"}}'
-e 'dnd_pipeline_notarius_testing_llm_profile=gpt-terra-latest'
-e '{"dnd_pipeline_secrets":{"AUDITA_LLM_API_KEY":"audita-pipeline-synthetic-value","OPENROUTER_API_KEY":"notarius-pipeline-synthetic-value","OBJECT_STORAGE_KEY_ID":"object-storage-key-id-pipeline-synthetic-value","OBJECT_STORAGE_KEY":"object-storage-key-pipeline-synthetic-value"}}'
)
cleanup() {
@@ -36,6 +37,7 @@ trap cleanup EXIT
run_converge() {
output_file=$1
env -u AUDITA_LLM_API_KEY -u OPENROUTER_API_KEY \
-u OBJECT_STORAGE_KEY_ID -u OBJECT_STORAGE_KEY \
"$ansible_playbook" -i "$inventory" "${baseline_args[@]}" "$converge" | \
tee "$output_file"
}
@@ -64,11 +66,36 @@ run_converge "$baseline_log"
/usr/local/bin/audita config validate --config /usr/local/etc/audita/config.yml
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml \
--pipeline dnd-session
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml \
--config-profile testing --pipeline dnd-session
notarius_testing_config="$test_tmp/notarius-testing.yml"
/usr/local/bin/notarius config effective --config /usr/local/etc/notarius/config.yml \
--config-profile testing > "$notarius_testing_config"
/usr/local/bin/scriptorium inspect prompt \
--config /usr/local/etc/scriptorium/config.yml \
--prompt dnd.session_recap --prompt-version 2.0.0 --format json >/dev/null
/usr/bin/sudo -u narratio /usr/local/bin/narratio config validate \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs
/usr/bin/sudo -u narratio /usr/local/bin/narratio config validate \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs --profile testing
narratio_testing_config="$test_tmp/narratio-testing.yml"
/usr/bin/sudo -u narratio /usr/local/bin/narratio config show \
--config /usr/local/etc/narratio/pipeline.yml --campaign centaurs --profile testing \
> "$narratio_testing_config"
"$workspace_venv/bin/python" - \
"$notarius_testing_config" "$narratio_testing_config" <<'PY'
import sys
import yaml
with open(sys.argv[1], encoding="utf-8") as config_file:
notarius = yaml.safe_load(config_file)
with open(sys.argv[2], encoding="utf-8") as config_file:
narratio = yaml.safe_load(config_file)
assert notarius["pipelines"]["dnd-session"]["llm_profile"] == "gpt-terra-latest"
assert narratio["notarius"]["config_profile"] == "testing"
PY
repeat_log="$test_tmp/repeat.log"
run_converge "$repeat_log"