Compare commits

...

167 Commits

Author SHA1 Message Date
31c01f0fce Close out the Scriptorium credential update 2026-09-29 20:04:11 +00:00
7f957e14bc Record the Scriptorium credential update handoff 2026-09-29 18:47:03 +00:00
ed91180899 Record local consumer credential revision 2026-09-29 18:46:27 +00:00
827c734fdd Record public D&D collection credential revision 2026-09-29 18:44:25 +00:00
62f5f5e93f Record public D&D pipeline credential revision 2026-09-29 18:40:30 +00:00
2d2f67f66e Record public Narratio credential role revision 2026-09-29 18:19:04 +00:00
e1aa245054 Plan the Narratio Scriptorium credential update 2026-09-29 18:10:17 +00:00
43ecdebcc5 Close out the coordinated suite upgrade 2026-09-29 15:17:31 +00:00
6829439807 Record resolution of the suite upgrade review findings 2026-09-29 15:10:17 +00:00
fec2f89b48 Record coordinated suite upgrade validation 2026-09-29 14:58:35 +00:00
1f41045830 Record consumer upgrade preparation 2026-09-29 14:55:59 +00:00
f964b24f7e Record validated collection assembly revision 2026-09-29 14:51:58 +00:00
8b8c232043 Record validated pipeline assembly revision 2026-09-29 14:46:31 +00:00
1b1382fe6e Record suite configuration migration completion 2026-09-29 14:32:20 +00:00
c0a0dae794 Record the coordinated suite upgrade in progress 2026-09-29 14:16:57 +00:00
82e672b888 Record Gitea publication blocker 2026-09-29 14:11:02 +00:00
f084988c80 Prepare the coordinated suite upgrade sprint 2026-09-29 14:08:18 +00:00
005a1c8ad5 Close out the standalone Narratio upgrade 2026-09-29 13:16:41 +00:00
ced9e66382 Record Narratio upgrade validation 2026-09-28 14:55:53 +00:00
0dc7e5b965 Record Narratio selector validation 2026-09-28 14:54:06 +00:00
2477189047 Record the Narratio upgrade in progress 2026-09-28 14:50:08 +00:00
8c689ea113 Prepare the Narratio upgrade implementation sprint 2026-09-28 14:43:11 +00:00
e93ebea771 Close out the standalone Notarius upgrade 2026-09-28 14:36:06 +00:00
a0414244bb Record Notarius upgrade validation 2026-09-28 14:14:58 +00:00
ae8d93f71a Record Notarius retry validation 2026-09-28 14:13:33 +00:00
bcaf48155e Record the Notarius upgrade in progress 2026-09-28 14:09:01 +00:00
760a172b34 Prepare the Notarius upgrade implementation sprint 2026-09-28 14:06:57 +00:00
8111f66de5 Close out the standalone Audita upgrade 2026-09-28 13:52:04 +00:00
f58c960b56 Record the standalone Audita upgrade for review 2026-09-28 13:48:14 +00:00
5301dac921 Record completion of Audita configuration coverage 2026-09-28 13:45:52 +00:00
c0582faa24 Record completion of Audita version 2 role migration 2026-09-28 13:42:24 +00:00
e0153d938b Plan the standalone Audita version 2 upgrade 2026-09-28 13:33:47 +00:00
86836879eb Close out the standalone Scriptorium upgrade 2026-09-28 13:16:30 +00:00
e7f5e4753a Record the standalone Scriptorium upgrade for review 2026-09-28 03:52:37 +00:00
98abc1b905 Record completion of Scriptorium configuration interface 2026-09-28 03:50:16 +00:00
aa9338b135 Record completion of Scriptorium version adoption 2026-09-28 03:44:53 +00:00
5a8e3fccc9 Plan the standalone Scriptorium upgrade 2026-09-28 03:40:04 +00:00
3bc042ea22 Close out the Notarius testing overlay feature 2026-09-22 19:25:35 +00:00
47129b213d Record the Notarius testing overlay implementation for review 2026-09-22 19:01:09 +00:00
8cd642ffa6 Record the testing overlay collection snapshot 2026-09-22 18:57:31 +00:00
ad739671f6 Record the Notarius testing overlay implementation 2026-09-22 18:52:52 +00:00
0b2a45a327 Record the Notarius v0.7.1 role update 2026-09-22 18:36:23 +00:00
59b472d0a1 Record the Narratio profile selector implementation 2026-09-22 18:33:46 +00:00
38dfb0422c Plan the Notarius testing overlay implementation 2026-09-22 18:23:20 +00:00
58738e4efc Close out the D&D deployment playbook feature 2026-09-21 14:19:47 +00:00
a231b57294 Record D&D playbook preparation for review 2026-09-21 05:16:25 +00:00
1d1f34fc8b Limit the D&D feature to playbook preparation 2026-09-21 05:14:06 +00:00
f9901f17d1 Remove unnecessary deployment gates and record preparation 2026-09-21 05:04:47 +00:00
f8fe8dd0c6 Record role documentation compatibility blocker 2026-09-21 04:52:36 +00:00
e482ea4b01 Close storage review and begin host deployment 2026-09-21 04:48:54 +00:00
bbb7acc315 Separate local preparation from deployment prerequisites 2026-09-21 04:46:49 +00:00
d0c776b47e Record D&D deployment blockers 2026-09-21 04:37:52 +00:00
45599bb020 Prepare the D&D host deployment sprint 2026-09-21 04:31:36 +00:00
bb0f8cf84b Mark implementation handoff complete 2026-09-21 03:41:02 +00:00
76c10f79f5 Record D&D storage and publishing implementation 2026-09-21 03:40:52 +00:00
f399be34cd Mark pipeline collection import complete 2026-09-21 03:39:52 +00:00
2feb622937 Mark collection credential fixture complete 2026-09-21 03:36:37 +00:00
974b57e33e Mark D&D storage policy complete 2026-09-21 03:35:45 +00:00
a95a0ea280 Resume D&D storage and publishing plan 2026-09-21 03:20:03 +00:00
e262b61292 Plan D&D S3 storage and publishing 2026-09-21 02:20:57 +00:00
ec69f5a03b Mark operator enrollment handoff complete 2026-09-18 13:01:20 +00:00
bf81461de6 Record pipeline operator enrollment implementation 2026-09-18 13:01:07 +00:00
839b63a61e Mark collection operator enrollment import complete 2026-09-18 13:00:28 +00:00
3233bf6b9b Mark pipeline operator enrollment complete 2026-09-18 12:56:32 +00:00
a5bc701f60 Plan pipeline operator enrollment 2026-09-18 12:44:26 +00:00
eda361fa5d Complete the first suite release 2026-09-17 23:52:46 +00:00
06e1b35f25 Mark first suite release handoff complete 2026-09-17 20:08:24 +00:00
539c75cb18 Record the first suite release implementation 2026-09-17 20:08:09 +00:00
fc8f5709b0 Mark public release validation complete 2026-09-17 20:07:08 +00:00
0e0034ef02 Mark collection release published 2026-09-17 20:03:11 +00:00
40ca08a352 Mark collection release candidate complete 2026-09-17 19:20:26 +00:00
956c50cc2f Mark pipeline role release published 2026-09-17 19:16:27 +00:00
e24e8d0d05 Mark application role tags published 2026-09-17 18:57:34 +00:00
943ece7a65 Mark application role release validation complete 2026-09-17 18:56:42 +00:00
b98fb5783f Plan the first coordinated suite release 2026-09-17 18:44:56 +00:00
253d283234 Complete the D&D collection assembly 2026-09-17 14:24:03 +00:00
8f57e1bcf5 Mark Feature 0012 handoff complete 2026-09-17 03:46:56 +00:00
b359eee321 Record the Feature 0012 implementation 2026-09-17 03:46:47 +00:00
2b1448ab91 Mark collection integration testing complete 2026-09-17 03:46:10 +00:00
ec3c0b9706 Mark pipeline subtree import complete 2026-09-17 03:32:19 +00:00
1a81db660e Mark collection foundation stage complete 2026-09-17 03:30:14 +00:00
bc1cf31f0e Mark collection usage documentation complete 2026-09-17 03:28:59 +00:00
9a86cdb57e Plan the D&D collection assembly 2026-09-17 03:26:04 +00:00
54a2362c02 Close Feature 0011 after remediation 2026-09-16 21:37:17 +00:00
d2bd48cc99 Record the pipeline credential implementation 2026-09-16 20:06:35 +00:00
731a799873 Mark pipeline credential documentation stage complete 2026-09-16 20:06:05 +00:00
bbc8d25d64 Mark pipeline credential delivery stage complete 2026-09-16 19:51:05 +00:00
9b0949f2ac Mark Narratio upgrade stage complete 2026-09-16 19:24:46 +00:00
358051af98 Prepare the managed credential implementation sprint 2026-09-16 19:12:42 +00:00
6d9b4b87f8 Complete the D&D Notarius integration feature 2026-09-15 22:19:28 +00:00
7ac9220e87 Record the D&D Notarius integration implementation 2026-09-15 21:01:19 +00:00
7f8ce88b43 Record documentation and testing completion 2026-09-15 21:00:45 +00:00
5b2effd68a Record completion of the D&D pipeline integration 2026-09-15 20:49:10 +00:00
88a0eaacf5 Record completion of the Notarius role upgrade 2026-09-15 20:05:28 +00:00
1806bfaf7f Prepare the D&D Notarius integration sprint 2026-09-15 19:55:48 +00:00
f91871ba0f Complete the shared pipeline filesystem feature 2026-09-15 15:02:05 +00:00
69961180a2 Record shared pipeline implementation validation 2026-09-15 01:11:43 +00:00
f605fa0c1a Mark shared pipeline execution documentation complete 2026-09-15 00:47:14 +00:00
1e0d4d0788 Mark cross-identity pipeline access testing complete 2026-09-15 00:39:04 +00:00
dcc1103358 Mark shared pipeline ACL management complete 2026-09-15 00:14:49 +00:00
daa08e6156 Mark shared configuration ownership complete 2026-09-15 00:05:36 +00:00
fa348e9376 Clear the shared pipeline dependency blocker 2026-09-14 23:49:08 +00:00
7d92867ba7 Record the remaining shared filesystem work 2026-09-14 23:47:28 +00:00
398562a2ca Record shared pipeline dependency publication blocker 2026-09-14 14:05:50 +00:00
efc7905798 Mark Narratio configuration ownership complete 2026-09-14 14:05:06 +00:00
8143732741 Mark Scriptorium configuration ownership complete 2026-09-14 14:00:13 +00:00
cb90d63a2b Mark Notarius configuration ownership complete 2026-09-14 13:57:06 +00:00
52fa8ac918 Mark Audita configuration ownership complete 2026-09-14 13:54:01 +00:00
f6b6c7196b Prepare the shared pipeline filesystem sprint 2026-09-14 13:45:55 +00:00
a7d718970f Document shared pipeline filesystem policy 2026-09-14 13:02:12 +00:00
e63b334887 Complete the D&D processing configuration feature 2026-09-11 04:40:48 +00:00
562eb540b8 Mark processing configuration documentation complete 2026-09-11 02:45:26 +00:00
870fc7b739 Mark processing configuration tests complete 2026-09-11 02:38:30 +00:00
9f0d11d897 Mark Narratio processing configuration complete 2026-09-11 02:23:42 +00:00
663dce1a9c Mark Audita policy complete 2026-09-11 02:10:28 +00:00
b83b778751 Prepare the D&D processing configuration sprint 2026-09-11 02:03:17 +00:00
daab85ae7e Complete D&D asset deployment 2026-09-10 17:20:20 +00:00
fb3c95d462 Mark asset integration coverage complete 2026-09-10 15:48:22 +00:00
ca0380b208 Mark asset deployment complete 2026-09-10 15:43:53 +00:00
3b2c47d236 Mark prompt asset corrections complete 2026-09-10 15:42:02 +00:00
4765586004 Mark campaign alignment complete 2026-09-10 15:41:17 +00:00
5fdd92b297 Plan D&D asset deployment 2026-09-10 15:37:00 +00:00
e46c8182f1 Complete the pipeline composition foundation 2026-09-10 14:58:31 +00:00
0beda58192 Mark pipeline composition coverage complete 2026-09-10 14:30:41 +00:00
05f100e2bf Mark pipeline role composition stage complete 2026-09-10 14:26:37 +00:00
a84a6383ec Plan the pipeline role composition foundation 2026-09-10 14:06:00 +00:00
8e34f56f81 Complete the Narratio role feature 2026-09-09 22:27:52 +00:00
e418edc5ef Mark Narratio integration coverage stage complete 2026-09-09 21:50:02 +00:00
e7607f45f7 Mark Narratio role stage complete 2026-09-09 21:45:13 +00:00
7c2c9fe287 Plan the standalone Narratio role 2026-09-09 21:33:44 +00:00
860651966a Complete the Scriptorium feature 2026-09-09 19:17:08 +00:00
6034691350 Mark Scriptorium integration coverage stage complete 2026-09-09 14:42:24 +00:00
8150dd2555 Mark Scriptorium role stage complete 2026-09-09 14:37:03 +00:00
bbeecc0055 Plan the Scriptorium role implementation 2026-09-09 14:20:26 +00:00
77dcf8f7f7 Align the Notarius roadmap with testing policy 2026-09-09 13:59:42 +00:00
3f20cf4b18 Organize workspace policies by task 2026-09-09 13:20:46 +00:00
332bc4742b Complete the test suite remediation 2026-09-09 13:03:24 +00:00
6d6b2307ff Mark test suite remediation complete 2026-09-09 04:36:48 +00:00
ca82dd76aa Record the test suite remediation results 2026-09-09 04:36:39 +00:00
e4a307578c Mark Notarius test suite stage complete 2026-09-09 04:31:02 +00:00
9ceaa2a5f1 Mark Audita test suite stage complete 2026-09-09 04:27:53 +00:00
1714b60dfe Mark Seriatim test suite stage complete 2026-09-09 04:25:08 +00:00
482e8473c2 Plan classical test suite remediation 2026-09-09 04:19:51 +00:00
4177b4de81 Complete the Notarius feature 2026-09-08 23:53:06 +00:00
f87962ca13 Record the Notarius implementation plan and review 2026-09-08 23:45:08 +00:00
5dc879ecd7 Define the Notarius configuration interface 2026-09-08 17:55:46 +00:00
a3af153895 Complete the Audita amendment and resume Notarius planning 2026-09-08 14:03:14 +00:00
5713ce582e Complete the Audita feature 2026-09-08 04:42:11 +00:00
007d8b830e Mark Audita integration coverage complete 2026-09-08 04:07:16 +00:00
0b7d6d98a7 Mark Audita installation complete 2026-09-08 03:49:27 +00:00
c297f56b7e Prepare the Audita implementation sprint 2026-09-08 03:34:03 +00:00
da799198b2 Document the completed Seriatim remediation 2026-09-08 02:09:23 +00:00
a1be51ea35 Mark focused Seriatim coverage complete 2026-09-08 01:13:11 +00:00
81ea76aa51 Mark Seriatim role simplification complete 2026-09-08 01:07:34 +00:00
4e8018405a Prepare the Seriatim simplification sprint 2026-09-08 00:53:06 +00:00
fc803587b8 Revise the Seriatim plan and workspace conventions 2026-09-08 00:16:12 +00:00
aafee9ea62 Mark Seriatim source installation complete 2026-09-07 20:46:16 +00:00
8e7af0cebf Record completion of Seriatim remediation 2026-09-07 20:41:08 +00:00
a5d032e2dc docs: record Seriatim remediation completion 2026-09-07 19:14:22 +00:00
819ccb155f docs: record Seriatim remediation findings 2026-09-07 18:51:14 +00:00
a1b340be0c docs: mark Seriatim integration stage complete 2026-09-07 18:17:18 +00:00
8122df641b docs: mark Seriatim build stage complete 2026-09-07 18:09:36 +00:00
0c738f4a94 docs: mark Seriatim source prerequisites stage complete 2026-09-07 18:04:07 +00:00
1251143a34 docs: mark Seriatim role contract stage complete 2026-09-07 18:00:04 +00:00
a556734cc2 Prepare the Seriatim source installation plan 2026-09-07 17:52:25 +00:00
fc9f818598 docs: define initial Seriatim installation feature 2026-09-07 17:37:03 +00:00
4e861f1f3e docs: establish staged feature planning workflow 2026-09-07 17:14:21 +00:00
50 changed files with 9000 additions and 160 deletions

3
.gitignore vendored
View File

@@ -7,9 +7,12 @@
/ansible-role-scriptorium/ /ansible-role-scriptorium/
/ansible-role-seriatim/ /ansible-role-seriatim/
/rakestraw-ansible/ /rakestraw-ansible/
/assets/campaigns/
/assets/narratio-prompts/
# Local tool state. # Local tool state.
/.codebase-memory/ /.codebase-memory/
/.venv/
/.idea/ /.idea/
/.vscode/ /.vscode/
*.swp *.swp

View File

@@ -7,71 +7,18 @@ deploy the D&D transcript-processing pipeline. It owns cross-repository plans,
decisions, status, and workspace tooling. Each application and Ansible project decisions, status, and workspace tooling. Each application and Ansible project
is an independent Git repository. is an independent Git repository.
## Repository Map ## Required Reading
Repositories inside this directory: - Read [the workspace orientation](docs/orientation.md) before selecting,
inspecting, or modifying a repository. It maps the repositories and defines
- `ansible-collection-dnd`: the `rakestraw.dnd` collection that bundles and the canonical sources of truth.
distributes the pipeline suite. - Read [the workspace conventions](docs/conventions.md) before making any
- `ansible-role-dnd-pipeline`: independent source repository for the repository change. They define the workspace-wide rules and route work to
suite-level role exposed by the collection as `rakestraw.dnd.pipeline`. specialized policy.
- `ansible-role-{narratio,notarius,audita,seriatim,scriptorium}`: standalone - Read [the Ansible house style](docs/ansible.md) before designing,
application roles. implementing, or reviewing Ansible roles or collections, including plans
- `rakestraw-ansible`: working deployment repository containing the that specify such work.
`pipeline_dnd` proof of concept; treat it as read-only reference unless the - Read [the testing house style](docs/testing.md) before creating, changing,
task explicitly includes it. reviewing, or auditing tests, including plans that specify test work.
- Read [the planning policy](docs/planning.md) before preparing a feature
Relevant upstream repositories are siblings of this directory: roadmap or implementation plan or managing an ongoing work stream.
- `../{narratio,notarius,audita,seriatim,scriptorium}`: application source and
authoritative application contracts.
- `../narratio-prompts`: pipeline prompt-library content.
Use `workspace.yml` as the complete machine-readable inventory of paths and
remotes.
## Sources of Truth
- `docs/roadmap/mvp.md`: settled MVP scope, architecture, and open design work.
- `docs/status.md`: current cross-repository progress and next work.
- `docs/decisions/`: durable rationale for significant architectural choices.
- `docs/plans/`: temporary implementation plans for substantial work.
- Application repositories: CLI, configuration, build, and integration
contracts.
- Individual Ansible repositories: implementation and repository-local tests.
Do not duplicate an application contract in workspace documentation when a
link and a concise deployment consequence are sufficient.
## Working Conventions
- Confirm the target repository before editing; never treat this directory as
a monorepo.
- Inspect the relevant upstream application before designing or changing its
Ansible role.
- Keep standalone application roles independently usable. Cross-application
policy belongs in `ansible-role-dnd-pipeline` and is exposed to consumers as
`rakestraw.dnd.pipeline`.
- Use `ansible.builtin` modules directly unless a concrete requirement justifies
another dependency.
- Prefer codebase-memory graph tools for code discovery. Use text/file search
for documentation, configuration, literals, or when the graph is
insufficient.
- Preserve unrelated and pre-existing working-tree changes in every
repository.
- Never place credentials or secret values in plans, examples, inventory, or
tests.
- Validate changes in the repository that owns them and report the commands
run.
## Planning and Progress
- Update `docs/roadmap/mvp.md` when a design question becomes a settled scope
or architecture decision.
- Update `docs/status.md` when cross-repository work starts, becomes blocked,
or is completed. Completed items must point to concrete evidence.
- Create a file in `docs/plans/` only for work spanning multiple meaningful
steps or repositories. Remove or archive stale execution detail after the
work is complete; durable rationale belongs in `docs/decisions/`.
- Use the status values `proposed`, `ready`, `in_progress`, `blocked`, `done`,
and `deferred`.

View File

@@ -7,17 +7,39 @@ only workspace documentation, planning, and shared development utilities.
## Start Here ## Start Here
- [`AGENTS.md`](AGENTS.md) describes repository boundaries and working - [`AGENTS.md`](AGENTS.md) describes repository boundaries and routes each
conventions. kind of work to its required policy documents.
- [`workspace.yml`](workspace.yml) inventories the repositories used during - [`workspace.yml`](workspace.yml) inventories the repositories used during
development. development.
- [`docs/roadmap/mvp.md`](docs/roadmap/mvp.md) records settled MVP decisions - [`docs/roadmap/mvp.md`](docs/roadmap/mvp.md) records settled MVP decisions
and open design work. and open design work.
- [`docs/roadmap/features/`](docs/roadmap/features/) contains durable feature
roadmaps for selected units of work.
- [`docs/status.md`](docs/status.md) records current cross-repository progress. - [`docs/status.md`](docs/status.md) records current cross-repository progress.
- [`docs/roadmap/implementation.md`](docs/roadmap/implementation.md), when
present, is the single active out-of-band implementation plan.
- [`docs/roadmap/implementation-template.md`](docs/roadmap/implementation-template.md)
defines its staged format.
Run `./scripts/status` to see the branch and working-tree state of every Run `./scripts/status` to see the branch and working-tree state of every
repository in the workspace manifest. repository in the workspace manifest.
## Development Tooling
Create the shared workspace environment on Ubuntu 26.04 with:
```sh
sudo apt-get install python3-venv
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -r requirements-dev.txt
```
Either activate it with `source .venv/bin/activate` or invoke tools directly,
for example `.venv/bin/ansible-playbook` and `.venv/bin/ansible-lint`.
Dependency upgrades are deliberate changes to `requirements-dev.txt`; do not
install workspace development packages into the system Python environment.
## Repository Boundaries ## Repository Boundaries
The directories ignored by this repository are intentional nested Git working The directories ignored by this repository are intentional nested Git working

View File

@@ -0,0 +1,52 @@
# Ansible managed
version: 1
pipeline:
modules: ['glossary', 'homophones', 'glossary', 'spoken_word', 'grammar']
output:
schema: audita-v1
llm:
proposal:
base_url: https://inference.ai.rakestrawhome.com/v1
model: google/gemma-4-31b-it
api_key_env: AUDITA_LLM_API_KEY
timeout: 900s
max_retries: 3
validation:
base_url: https://inference.ai.rakestrawhome.com/v1
model: google/gemma-4-31b-it
api_key_env: AUDITA_VALIDATION_LLM_API_KEY
timeout: 900s
max_retries: 3
concurrency:
total_llm: 4
proposal_llm: 4
validation_llm: 4
chunking:
target_sections: 8
max_section_tokens: 6144
min_section_tokens: 2048
normalization:
max_segment_gap: 3s
ellipsis_gap: 3s
max_segment_duration: 240s
max_segment_tokens: 2048
thresholds:
glossary: 0.8
homophones: 0.8
spoken_word: 0.8
grammar: 0.8
context:
description: "The following transcript was recorded during a Dungeons & Dragons game session. It may contain some unrelaed pre-session or post-session banter, in addition to actual D&D gameplay."
diagnostics:
work_dir: /tmp/audita
retention: auto

View File

@@ -0,0 +1,160 @@
workspace:
root: /var/lib/narratio
cleanup_after_publish: true
secrets:
env_dir: /usr/local/etc/narratio/secrets
campaigns:
root: /usr/local/etc/narratio/campaigns
default_campaign_id: dilfs
storage:
backend: s3
s3:
endpoint: "https://s3.us-east-005.backblazeb2.com"
bucket: "rakestraw-assets"
root_prefix: "dnd"
region: "us-east-1"
force_path_style: True
access_key_id_env: OBJECT_STORAGE_KEY_ID
secret_access_key_env: OBJECT_STORAGE_KEY
whisperx:
transcribe_url: https://transcription.ai.rakestrawhome.com/transcribe
publish:
enabled: true
upload_run: true
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
dest: artifacts/session_recap.md
required: true
- source: narratio.artifact.hostile_rumors
dest: artifacts/hostile_rumors.md
required: true
- source: narratio.artifact.deranged_rumors
dest: artifacts/deranged_rumors.md
required: false
scriptorium:
binary: scriptorium
config_path: /usr/local/etc/scriptorium/config.yml
timeout: 10m
render_debug: false
artifacts:
session_recap:
enabled: true
prompt_id: dnd.session_recap
profile_id: claude-fable-latest
output_path: artifacts/session_recap.md
timeout: 10m
inputs:
transcript:
source: narratio.transcript.final_trimmed
required: true
players:
source: narratio.input.players
required: true
party:
source: narratio.input.party
required: true
# recap:
# source: narratio.previous_session.artifact.session_recap
# required: false
scene_map:
enabled: false
prompt_id: dnd.scene_map
profile_id: claude-haiku-latest
output_path: artifacts/scene_map.json
timeout: 10m
inputs:
transcript:
source: narratio.transcript.final_trimmed
required: true
players:
source: narratio.input.players
required: true
party:
source: narratio.input.party
required: true
character_meta_analysis_alan:
enabled: false
prompt_id: dnd.character_meta_analysis
profile_id: claude-fable-latest
output_path: artifacts/character_meta_analysis_alan.md
timeout: 10m
inputs:
transcript:
source: narratio.transcript.final_trimmed
required: true
players:
source: narratio.input.players
required: true
party:
source: narratio.input.party
required: true
recap:
source: narratio.previous_session.artifact.session_recap
required: false
vars:
character_name: "Alan"
character_class: "Druid"
character_meta_analysis_hrank:
enabled: false
prompt_id: dnd.character_meta_analysis
profile_id: claude-fable-latest
output_path: artifacts/character_meta_analysis_hrank.md
timeout: 10m
inputs:
transcript:
source: narratio.transcript.final_trimmed
required: true
players:
source: narratio.input.players
required: true
party:
source: narratio.input.party
required: true
recap:
source: narratio.previous_session.artifact.session_recap
required: false
vars:
character_name: "Hrank"
character_class: "Cleric"
hostile_rumors:
enabled: true
prompt_id: dnd.hostile_rumors
output_path: artifacts/hostile_rumors.md
timeout: 10m
depends_on:
- session_recap
inputs:
recap:
source: narratio.artifact.session_recap
required: true
deranged_rumors:
enabled: true
prompt_id: dnd.deranged_rumors
output_path: artifacts/deranged_rumors.md
timeout: 10m
depends_on:
- session_recap
inputs:
recap:
source: narratio.artifact.session_recap
required: true

View File

@@ -0,0 +1,154 @@
version: 4
output:
directory: /var/lib/notarius/output
debug:
directory: /var/lib/notarius/debug
cache:
chunk_plans:
mode: auto
directory: /var/lib/notarius/cache/chunk_plans
checkpoints:
enabled: true
directory: /var/lib/notarius/cache/checkpoints
pipelines:
dnd-session:
llm_profile: dnd-extraction
# llm_profile: rakestrawhome-gemma-4-31b
input: seriatim
# Stable campaign context is shared by every module that accepts these slots.
references:
party: /usr/local/etc/notarius/campaigns/centaurs/party.yml
glossary: /usr/local/etc/notarius/campaigns/centaurs/glossary.yml
chunk:
module: dnd/scenes
retries: 2
output:
module: json
options:
include_chunk_map: true
evidence_context:
enabled: true
window_units: 3
lanes:
- item-occurrences
- item-registry
- location-registry
- location-occurrences
- npc-registry
- spells
- combat-turns
- npc-occurrences
- enemy-events
steps:
# Establish session-wide reference artifacts before their consumers.
- id: describe-session
artifacts:
item-registry:
extract:
module: dnd/item-registry
retries: 2
merge: appendorder
normalize: dnd/item-registry
npc-registry:
extract:
module: dnd/npc-registry
retries: 2
merge: appendorder
normalize:
module: dnd/npc-registry
retries: 2
location-registry:
extract:
module: dnd/location-registry
retries: 2
merge: appendorder
normalize:
module: dnd/location-registry
retries: 2
scene-descriptions:
extract:
module: dnd/scene-descriptions
retries: 2
merge: appendorder
normalize: dnd/scene-descriptions
- id: extract-events
# Accepted registry artifacts and scene-description eligibility artifacts
# are supplied in memory to their compatible consumers in this step.
references:
location_registry:
artifact:
step: describe-session
lane: location-registry
npc_registry:
artifact:
step: describe-session
lane: npc-registry
scene_descriptions:
artifact:
step: describe-session
lane: scene-descriptions
item_registry:
artifact:
step: describe-session
lane: item-registry
artifacts:
item-occurrences:
extract:
module: dnd/item-occurrences
retries: 2
merge: appendorder
normalize: dnd/item-occurrences
spells:
extract:
module: dnd/spells
retries: 2
merge: appendorder
normalize:
module: dnd/spells
combat-turns:
extract:
module: dnd/combat-turns
retries: 2
merge: appendorder
normalize: dnd/combat-turns
npc-occurrences:
extract:
module: dnd/npc-occurrences
retries: 2
merge: appendorder
normalize: dnd/npc-occurrences
location-occurrences:
extract:
module: dnd/location-occurrences
retries: 2
merge: appendorder
normalize: dnd/location-occurrences
- id: track-enemies
references:
npc_registry:
artifact:
step: describe-session
lane: npc-registry
scene_descriptions:
artifact:
step: describe-session
lane: scene-descriptions
combat_turns:
artifact:
step: extract-events
lane: combat-turns
npc_occurrences:
artifact:
step: extract-events
lane: npc-occurrences
artifacts:
enemy-events:
extract:
module: dnd/enemy-events
retries: 2
merge: appendorder
normalize: dnd/enemy-events

View File

@@ -0,0 +1,5 @@
# Ansible managed
prompt_dir: /usr/local/etc/scriptorium/library/prompts
profile_dir: /usr/local/etc/scriptorium/library/profiles
schema_dir: /usr/local/etc/scriptorium/library/schemas

97
docs/ansible.md Normal file
View File

@@ -0,0 +1,97 @@
# Ansible House Style
This policy is normative for designing, implementing, and reviewing Ansible
roles and collections in this workspace.
## Role Implementation
- Always use the smallest clear sequence of declarative tasks that reaches the
required end state.
- Prefer `ansible.builtin` modules where they directly fit the task.
`community.general` is an approved, stable dependency and its modules may be
selected freely when appropriate; declare and pin the collection wherever a
role or collection depends on it.
- Do not strengthen the specification. Implement the requested invariants
without inventing additional guarantees for integrity, provenance, drift
recovery, corruption detection, rollback, or similar behavior.
- Prefer convergence over state inspection. Declare what should be true and
let the relevant module reconcile it.
- Trust Ansible's abstraction boundary. A module that manages state owns the
checks necessary to manage that state. Inspect it beforehand only when the
observed state is independently required.
- State inspection is justified when its result is necessary to decide whether
an imperative operation must run, such as checking whether an arbitrary
build command's output exists.
- Production role tasks establish required application state; they do not test
the role's own implementation. Put implementation verification in
repository-local tests unless the specification explicitly requires runtime
validation during convergence.
- For an unavoidable `command` or `shell` task, declare the operation's change
semantics as required by ansible-lint. A conditionally executed mutation may
use `changed_when: true`; a read-only command should use
`changed_when: false`. This describes an imperative operation and does not
replace the idempotence of a state-management module.
- Apply `become: true` to individual tasks that require elevated privileges.
Do not require callers to escalate an entire play merely to use a role.
- Complexity requires a requirement. Every additional task, conditional,
registered variable, or state probe must correspond to behavior the role is
required to provide.
- Persisted role-private state is a design smell. Fingerprints, checksum
databases, stamps, manifests, and similar bookkeeping require specific
justification.
- **Assume convergence first.** Before adding machinery for an edge case,
determine whether rerunning the ordinary desired-state operations already
repairs it.
- Consider whether a conditional task or a notified handler best expresses the
dependency. A `when` condition keeps triggers visible at the action site but
grows with their number. Notifications keep the action independent of the
number of notifiers, but distribute the control flow and defer execution
until the next handler flush. An explicit
`ansible.builtin.meta: flush_handlers` affects all pending handlers in the
play.
- Treat `rakestraw-ansible` as a style reference for direct tasks, shallow
control flow, and concise variable use, while retaining current practices
such as fully qualified collection names.
## Application Configuration Interfaces
- Expose application configuration through documented, field-specific role
variables suitable for `host_vars`, `group_vars`, play variables, and
composing roles.
- Give structurally required fields concrete defaults. Define optional
application settings as `null` unless the role intentionally owns the
corresponding policy.
- Treat a null optional variable as "omit this field from the rendered
configuration." Do not copy documented upstream defaults into role defaults
merely to write them back to the application.
- Let the application supply its built-in defaults for omitted fields. This
avoids freezing a duplicate defaults database in Ansible and permits upstream
default changes to take effect naturally.
- Use `is not none` when conditionally rendering optional values. Do not use
truthiness, because false, zero, an empty string, or an empty collection may
be an intentional value.
- Emit a nested configuration section only when at least one of its descendant
variables is non-null.
- Serialize strings and collections with appropriate Ansible or Jinja filters.
Do not construct YAML quoting manually.
- Keep argument specifications aligned with the public variables. Optional
nullable variables are not required; use a permissive type only when the
native application accepts more than one scalar type.
- Prefer one field-specific interface. Do not provide a parallel raw mapping,
template override, or merge mechanism unless a concrete requirement defines
its precedence and behavior.
- Application roles expose native configuration choices. The suite-level role
supplies cross-application and deployment-specific policy through those
variables.
- Manage the resulting file with one ordinary `ansible.builtin.template` task.
Do not add configuration assembly facts, preliminary file inspection, or
production validation unless independently required.
- Configuration tests should use explicitly supplied representative values to
exercise conditional rendering, null omission, intentional falsey values,
native configuration validity, and caller-facing composition boundaries.
They should follow [the testing house style](testing.md) rather than
snapshotting the current default document.
Role defaults define what Ansible intends to manage, not a mirror of every
application default. A concrete default means the role deliberately owns that
policy; a null default leaves the policy with the application.

33
docs/conventions.md Normal file
View File

@@ -0,0 +1,33 @@
# Workspace Conventions
These conventions apply to all work in this workspace. Read the specialized
policy for the work being performed as well:
- Read [the Ansible house style](ansible.md) before designing, implementing,
or reviewing Ansible roles or collections, including their configuration
interfaces.
- Read [the testing house style](testing.md) before creating, changing,
reviewing, or auditing tests.
- Read [the planning policy](planning.md) before preparing or managing a
feature roadmap, implementation plan, or active work stream.
## Workspace-Wide Conventions
- Confirm the target repository before editing; never treat this directory as
a monorepo.
- Inspect the relevant upstream application before designing or changing its
Ansible role.
- Keep standalone application roles independently usable. Cross-application
policy belongs in `ansible-role-dnd-pipeline` and is exposed to consumers as
`rakestraw.dnd.pipeline`.
- Prefer codebase-memory graph tools for code discovery. Use text/file search
for documentation, configuration, literals, or when the graph is
insufficient.
- Preserve unrelated and pre-existing working-tree changes in every
repository.
- Never place credentials or secret values in plans, examples, inventory, or
tests.
- Validate changes in the repository that owns them and report the commands
run.
- Do not duplicate an application contract in workspace documentation when a
link and a concise deployment consequence are sufficient.

View File

@@ -0,0 +1,54 @@
# Decision 0001: Minimal, Module-Driven Ansible
Status: accepted
Date: 2026-09-07
## Context
The first Seriatim implementation surrounded ordinary Ansible operations with
preflight inspection, fingerprints, sidecar build state, manual drift logic,
and recovery behavior. Much of that machinery duplicated behavior already
provided by Ansible modules or addressed threats and failure modes outside the
MVP. The result was harder to understand, review, and maintain than the
deployment it represented.
The proof-of-concept roles in `rakestraw-ansible` demonstrate the preferred
style: direct module use, shallow task flow, small public interfaces, and
loops only for genuinely uniform resources.
## Decision
Roles in this workspace will express the required end state with the most
direct suitable Ansible module and trust that module's documented idempotence,
change detection, check-mode behavior, and error handling.
Additional inspection or state machinery is justified only when a selected
requirement falls outside that module contract. In particular:
- Do not use `stat`, package queries, content comparisons, or account lookups
merely to decide whether to invoke an idempotent module.
- Gather state when it is genuinely needed to control application behavior,
such as determining whether an imperative build command's output is missing.
- Treat a successful module invocation as establishing its documented
postcondition. Verify the role's implementation in repository-local tests
rather than adding production tasks that immediately re-prove it.
- Do not introduce fingerprints, checksums, sidecar state, staged replacement,
custom drift recovery, or abstractions without an explicit acceptance
criterion and rationale.
- Keep role variables to meaningful consumer choices. Do not expose every
fixed argument of an upstream build command as a public interface.
- Test the intended operating contract and idempotent convergence. Do not
build a speculative hardening test matrix into the MVP.
## Consequences
Feature roadmaps describe the simplest viable implementation shape, and
implementation plans must justify any material complexity beyond it. Reviews
should remove logic that merely reimplements a module's contract.
Potential security hardening and unusual recovery behavior may be recorded for
future consideration without becoming part of the initial implementation.
This accepts that an MVP role may fail plainly when the managed host contains
malicious, corrupted, or unsupported state rather than attempting automatic
recovery from every condition.

View File

@@ -0,0 +1,77 @@
# 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.
Narratio's general operational guidance recommends `0700` directories and
`0600` files for a single-user credential store. The suite deliberately grants
group read/traverse access instead: membership in the selected `narratio`
runtime group authorizes both pipeline execution and use of its shared provider
credentials. Deployments that do not trust every group member require a
different per-user credential policy and are outside this decision.
Version-controlled campaign and prompt assets may remain root-managed because
Git is authoritative, but they are world-readable. The suite does not add
confidentiality controls to non-secret D&D content.
## Consequences
The pipeline can run under the service account or an existing human member of
the shared group without maintaining separate configuration or cache trees.
The deployment must provision setgid and default ACL behavior on shared
writable roots; directory modes alone do not guarantee group write access for
content created under an arbitrary user umask.
The broad readability of transcript-derived content is intentional. Hosts
requiring confidential campaign data need a different deployment policy and
are outside this MVP contract. Secret delivery remains future work and must
honor the separate restricted subtree rather than tightening unrelated files.
Existing content with incompatible ownership or ACLs is not recursively
migrated unless a feature expressly selects that behavior. Fresh convergence
and newly created content follow this policy.

View File

@@ -6,3 +6,8 @@ change. Number records sequentially, for example
`0001-application-and-suite-role-boundaries.md`. `0001-application-and-suite-role-boundaries.md`.
Do not create a decision record for routine implementation choices. 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)

58
docs/orientation.md Normal file
View File

@@ -0,0 +1,58 @@
# Workspace Orientation
## Repository Map
Repositories inside this directory:
- `ansible-collection-dnd`: the `rakestraw.dnd` collection that bundles and
distributes the pipeline suite.
- `ansible-role-dnd-pipeline`: independent source repository for the
suite-level role exposed by the collection as `rakestraw.dnd.pipeline`.
- `ansible-role-{narratio,notarius,audita,seriatim,scriptorium}`: standalone
application roles.
- `assets/campaigns`: D&D campaign registry content deployed by the pipeline
role.
- `assets/narratio-prompts`: PromptKit-compatible prompts and schemas deployed
for Scriptorium by the pipeline role.
- `assets/configs`: snapshots of application configuration from a test machine;
treat them as non-authoritative operational references that may use obsolete
syntax or installation-specific values.
- `rakestraw-ansible`: working deployment repository containing the
`pipeline_dnd` proof of concept; treat it as read-only reference unless the
task explicitly includes it.
Relevant upstream repositories are siblings of this directory:
- `../{narratio,notarius,audita,seriatim,scriptorium}`: application source and
authoritative application contracts.
Use [the workspace inventory](../workspace.yml) as the complete
machine-readable inventory of paths and remotes.
## Sources of Truth
- [Workspace conventions](conventions.md): normative workspace-wide rules and
policy routing.
- [Ansible house style](ansible.md): normative role, collection, and
application-configuration practices.
- [Testing house style](testing.md): normative behavioral-testing practices.
- [Planning policy](planning.md): normative feature planning and progress
workflow.
- [MVP roadmap](roadmap/mvp.md): settled MVP scope, architecture, and open
design work.
- [Feature roadmaps](roadmap/features/): durable scope and target state for
selected units of work.
- [Workspace status](status.md): current cross-repository progress and next
work.
- [Decision records](decisions/): durable rationale for significant
architectural choices.
- [Implementation plan](roadmap/implementation.md): the fixed location for the
active staged plan or, when no plan is approved, a pending-plan notice.
- Application repositories: CLI, configuration, build, and integration
contracts.
- Asset repositories: authoritative campaign and prompt-library content and
layout.
- Reference configurations under `assets/configs`: evidence of prior
operational choices, never an application contract or a source to copy
verbatim.
- Individual Ansible repositories: implementation and repository-local tests.

48
docs/planning.md Normal file
View File

@@ -0,0 +1,48 @@
# Planning and Progress
- Read and follow [the workspace conventions](conventions.md) before preparing
or revising any roadmap or implementation plan. Also read the specialized
policy applicable to the planned work: [the Ansible house style](ansible.md),
[the testing house style](testing.md), or both.
- Update [the MVP roadmap](roadmap/mvp.md) when a design question becomes a
settled scope or architecture decision.
- Discuss and select the next unit of work before planning implementation.
- Give each selected feature a four-digit identifier and a durable document at
`docs/roadmap/features/<id>-<slug>.md`. Start from the
[feature-roadmap template](roadmap/features/template.md) and add the same
identifier to [workspace status](status.md).
- Write and agree on the feature roadmap before writing its implementation
plan. The roadmap owns scope, target end state, rationale, constraints, and
acceptance criteria.
- Every feature roadmap must describe its simplest viable implementation shape
and identify any deliberate complexity. Keep optional security hardening,
unusual corruption recovery, and other speculative resilience outside the
MVP unless explicitly selected as requirements.
- Start from the [implementation-plan template](roadmap/implementation-template.md)
and always write the current plan to
[the fixed implementation-plan location](roadmap/implementation.md). Replace
that file when planning the next selected feature; Git history preserves
prior plans when needed.
- When a prior plan has been withdrawn and its replacement has not yet been
agreed, replace stale execution instructions with a brief pending-plan
notice. Never leave an obsolete plan looking executable.
- Write implementation plans as dependency-ordered stages suitable for
GPT-5.6-Terra to execute sequentially. Number stages with consecutive
integers beginning with `Stage 1`; do not skip numbers or use nested stage
numbering. Each stage must identify its repository, preconditions, required
policy reading, behavior, validation, completion criteria, and expected
commit. Direct the implementing agent to reread the applicable policy
documents immediately before beginning each stage.
- Resolve architectural choices during roadmap and plan review. Do not leave
unresolved design judgment to the implementation agent.
- Update [workspace status](status.md) when cross-repository work starts,
becomes blocked, or is completed. Completed items must point to concrete
evidence.
- Out-of-band implementation should commit each completed stage when that
stage leaves its owning repository valid. Review the implementation and its
validation evidence before marking the feature complete.
- Retain feature roadmaps as durable records. Remove or archive obsolete
implementation detail after completion; durable architectural rationale
belongs in [decision records](decisions/).
- Use the status values `proposed`, `ready`, `in_progress`, `blocked`, `done`,
and `deferred`.

View File

@@ -1,37 +0,0 @@
# Plan: <Title>
Status: proposed
## Goal
State the outcome this plan must achieve.
## Non-goals
List adjacent work that is intentionally outside this plan.
## Owning Repositories
List every repository this work may change and what each repository owns.
## Dependencies and Settled Decisions
Link applicable roadmap sections and decision records. Record prerequisites
that constrain implementation.
## Acceptance Criteria
- Define observable conditions for completion.
## Implementation Sequence
1. Describe the first independently verifiable step.
## Validation
List the commands, tests, or inspections that demonstrate completion.
## Progress
Keep only concise current state and blockers here. Git history should preserve
obsolete execution detail.

View File

@@ -0,0 +1,88 @@
# Application Upgrade Sequence
Decision agreed: 2026-09-28
## Purpose and Order
Adopt the newly released applications through focused, individually reviewed
features in this order:
**Scriptorium → Audita → Notarius → Narratio → suite integration.**
This document tracks the cross-feature direction, not implementation steps.
Each feature roadmap owns its scope and decisions. Only one staged plan is
active at a time, at [implementation.md](implementation.md).
## Version Baseline
These are the suite pins at the start of this upgrade, not assertions about
what is installed on an operational host. Targets are the releases reviewed
on the decision date; later releases require deliberate review.
| Application | Starting suite version | Adoption target |
| --- | --- | --- |
| Scriptorium | v0.13.0 | v0.15.0 |
| Audita | v0.9.1 | v2.0.1 |
| Notarius | v0.7.1 | v0.8.1 |
| Narratio | v2.2.0 | v3.0.0 |
Seriatim is unchanged by this sequence.
## Progress and Feature Links
Release-summary and migration-guidance triage is complete. Standalone
Scriptorium, Audita, Notarius, and Narratio adoption are complete after independent
review. Coordinated suite integration and its three review remediations are
complete. This upgrade sequence was closed on 2026-09-29; operational deployment
and a new tagged release remain separate activities.
- [x] [Feature 0018: Scriptorium adoption](features/0018-scriptorium-v0-15-adoption.md) — complete through role `b174c8c`; independent review found no remediation issues.
- [x] [Feature 0019: Audita adoption](features/0019-audita-v2-adoption.md) — complete through role `c3dd59f`; independent review found no remediation issues.
- [x] [Feature 0020: Notarius adoption](features/0020-notarius-v0-8-adoption.md) — complete through role `6aef48b`; independent review found no remediation issues; suite unchanged.
- [x] [Feature 0021: Narratio adoption](features/0021-narratio-v3-adoption.md) — complete through role `3c0700b`; independent review found no remediation issues; suite unchanged.
- [x] [Feature 0022: Coordinated suite integration](features/0022-coordinated-suite-upgrade.md) — complete with three review findings resolved at public pipeline `37b1cf6`, public collection `b3bc045`, and local consumer `15f0f4e`.
## Adoption Boundaries
Completing a standalone-role update does **not** advance the suite's application
or role dependency pins, collection snapshot, or deployment-repository pins.
Keep that existing compatibility set until the final integration feature
assembles and validates the coordinated configuration.
Standalone features own generic application interfaces. The integration feature
owns D&D defaults, cross-application configuration, testing overlays, credential
references, compatible dependency pins, and consumer upgrade guidance. Each
feature follows roadmap → staged plan → implementation → review → closeout.
No operational deployment is authorized merely by this sequencing decision.
## Compatibility Constraints to Carry Forward
- **Scriptorium is not a documentation-only upgrade from our baseline.** The
intervening v0.14.0 introduces ConfigKit and changes configuration acceptance,
selection, and retry behavior. Review those changes as well as v0.15.0's
licensing and dependency updates.
- **Audita and Narratio need a coordinated suite cutover.** Audita v2 requires
migrated configuration; Narratio v3 expects that interface and no longer owns
the retired downstream settings or generated Audita configuration.
- **Overlay terminology changes on both sides of the Notarius boundary.**
Narratio's selector and the suite-managed downstream files must migrate
together. Preserve explicit selection and independent application ownership.
- **Existing Narratio manifests need operator migration guidance.** Carry the
upstream provenance-field migration into final integration planning. Preserve
session progress; do not infer a requirement to delete checkpoints, force all
stages, edit immutable remote snapshots, or automate the migration.
- **Review retry and timeout semantics explicitly.** New transport retry and
repair behavior is not necessarily equivalent to the previous settings.
Preserve user intent without copying old values mechanically or inventing
new suite policy.
The upstream documentation remains authoritative for exact fields and migration
procedures:
- [Scriptorium v0.14.0](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.14.0/docs/releases/v0.14.0.md)
and [v0.15.0](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/docs/releases/v0.15.0.md).
- [Audita v2 migration](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.1/docs/migrations/v2.md).
- [Notarius v0.8.0](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.8.0/docs/releases/v0.8.0.md)
and [v0.8.1](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.8.1/docs/releases/v0.8.1.md).
- [Narratio v3.0.0](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/releases/v3.0.0.md)
and [migration procedures](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/operations.md#migrating-manifest-overlay-provenance).

View File

@@ -0,0 +1,221 @@
# Feature 0001: Seriatim Source Installation
Status: done
## Summary
Provide a small, independently usable `rakestraw.seriatim` role that installs
Seriatim from a pinned Git tag, builds the native executable on the managed
host, and converges idempotently. This revised specification replaces the
original overengineered implementation target and establishes the preferred
module-driven style for subsequent application roles.
## Problem or Opportunity
The current role reaches the basic deployment outcome, but it does so with
manual source cleanup, compiler parsing, build-input serialization, hashes,
checksums, sidecar state, path-shape recovery, and a large defensive test
matrix. Those mechanisms are disproportionate to the MVP and obscure the
simple job of checking out a repository, building one executable, and
installing it with known metadata.
Seriatim remains the right proving ground because it has no central
configuration file. Simplifying it before implementing another role prevents
the current design from becoming an accidental suite-wide pattern.
## Scope
- Simplify `ansible-role-seriatim` into concise, idiomatic Ansible.
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
- Install Git and the official Go Snap with classic confinement when build
dependency management is enabled.
- Default the Go Snap channel to `1.26/stable`.
- Check out the selected Seriatim version from its official Git repository,
defaulting to immutable tag `v1.5.0`, under a root-owned
`/usr/local/src/seriatim`.
- Build Seriatim using the fixed upstream release build contract and install
it at `/usr/local/bin/seriatim`.
- Rebuild when the source checkout changes or the binary is absent.
- Converge the installed binary to `root:root` ownership and mode `0755`.
- Verify an explicitly selected immutable Seriatim version through the native
CLI in repository-local integration tests.
- Keep the role interface, README, metadata, and focused local tests consistent
with the simplified behavior.
- Remove obsolete build-state files and implementation machinery from the
role repository. Existing build-state data on previously managed hosts does
not need to be removed by the role.
## Non-goals
- Application configuration; Seriatim has no central configuration file.
- Creation or management of the `narratio` account or operator membership.
- Installation or configuration of any other pipeline application.
- Pipeline composition, campaign data, prompts, secrets, or scheduling.
- Installation from prebuilt release artifacts or removal behavior.
- Detecting rebuild needs from Go compiler changes, fixed build-command
changes, or out-of-band modification of an existing binary.
- Build fingerprints, binary checksums, or persistent sidecar build state.
- Transactional replacement that preserves a previous executable after a
failed local build.
- Automatic recovery from deliberately malformed paths, symbolic-link
redirection, hostile source trees, or other adversarial host state.
- A shared build helper role or abstraction.
- Dedicated platform-matrix infrastructure beyond the approved local MVP
proxy.
## Target End State
On an Ubuntu 26.04 `amd64` or `arm64` host, applying the role with default
variables installs Git and Go when requested, checks out Seriatim `v1.5.0`
under a root-owned `/usr/local/src/seriatim`, and installs a native executable at
`/usr/local/bin/seriatim`. The executable is owned by `root:root`, has mode
`0755`, and reports `seriatim version v1.5.0`.
An immediate second application makes no changes. A changed Git checkout or a
missing binary causes one build. The following application is again unchanged.
The role trusts `apt`, `community.general.snap`, `file`, and `git` to provide
their documented idempotence and change detection. It does not inspect state
before invoking those modules or maintain a parallel model of the state they
already manage.
## Repository Ownership
- `ansible-role-seriatim` owns the role implementation, defaults, metadata,
README, dependency declaration, and repository-local validation.
- `../seriatim` is the read-only authority for the build, version, and CLI
contracts.
- `rakestraw-ansible` is a read-only style reference.
- `ansible-workspace-dnd` owns this roadmap, the active implementation plan,
and cross-repository status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- The suite MVP supports Ubuntu 26.04 and native `amd64` and `arm64` builds.
- Local execution on the current Ubuntu 26.04 development host is a sufficient
MVP integration proxy.
- Go is installed from Snap with classic confinement and defaults to channel
`1.26/stable`.
- `community.general` is an approved dependency and provides Snap management;
its version is pinned in the role's collection requirements.
- The build runs from the checked-out source using `seriatim_go_binary`
(defaulting to `/snap/bin/go`) with `GOWORK=off`, `GOTOOLCHAIN=local`,
`CGO_ENABLED=0`, `-trimpath`, package `./cmd/seriatim`, and the upstream
linker flag that injects the selected version into
`internal/buildinfo.Version`.
- The selected version is both the Git revision and the version injected into
the executable. Supporting independent source and build identities is not an
MVP requirement.
- The public interface is limited to meaningful deployment choices:
`seriatim_version`, `seriatim_repository_url`, `seriatim_source_dir`,
`seriatim_binary_path`, `seriatim_manage_build_dependencies`,
`seriatim_go_snap_channel`, and `seriatim_go_binary`.
- Build flags, linker symbols, environment values, and package paths are
implementation details, not public variables.
- Tasks that install dependencies or manage root-owned application state use
task-level privilege escalation.
- `docs/decisions/0001-minimal-module-driven-ansible.md` governs the role's
implementation style.
## Simplest Viable Implementation
The intended Seriatim implementation is approximately the following eight
ordinary tasks.
1. Assert the supported distribution, release, and architecture.
2. Install Git with `ansible.builtin.apt` when dependency management is
enabled.
3. Install Go with `community.general.snap` when dependency management is
enabled.
4. Create the source and binary parent directories with one
`ansible.builtin.file` loop.
5. Check out the selected source with `ansible.builtin.git` and register its
normal changed result.
6. Inspect whether the installed binary exists.
7. Run the upstream Go build when the Git checkout changed or the binary is
absent.
8. Converge source ownership and the installed binary's ownership and mode
with one `ansible.builtin.file` loop.
For this fixed set of two rebuild triggers, the build remains an ordinary
task with the conditions applied directly to its `when` expression. This keeps
the complete decision visible at the action site and avoids deferred execution
or a play-wide handler flush. Permission convergence then follows in its
natural task order. Do not create an intermediate `seriatim_build_required`
fact.
The implementation may combine or split a task when required for clear and
correct Ansible, but it must not add preflight checks around idempotent modules
or reintroduce persistent build-state machinery. Prefer a single readable task
file unless a split materially improves navigation.
## Rationale and Alternatives
This design uses the Git module's changed result as the natural signal that
source changed. A binary existence check is the only additional state needed
to decide whether the imperative build command must run. That preserves useful
convergence without adding unrequested drift detection or maintaining a second
database of compiler and build inputs.
Building directly to the configured binary path is intentionally simpler than
staging, checksumming, and recording a transactional installation. A failed
build will fail the play visibly; preserving an older executable in every
failure mode is not an MVP requirement.
## Acceptance Criteria
- The role rejects unsupported distributions, Ubuntu releases, and
architectures before modifying application state.
- Default execution on the local Ubuntu 26.04 host installs or confirms Git
and Go and checks out Seriatim tag `v1.5.0`.
- The role builds with the documented fixed upstream contract and installs
`/usr/local/bin/seriatim` as `root:root` mode `0755`.
- The managed source checkout is owned by `root:root`.
- `/usr/local/bin/seriatim --version` reports
`seriatim version v1.5.0`.
- An immediate second role run reports no changes.
- A missing binary causes one rebuild followed by an unchanged run.
- A changed selected version causes the Git task and build task to change and
then converges.
- The implementation contains no build-input documents, fingerprints, binary
checksums, sidecar build state, manual Git reset or clean commands, or
preliminary checks for state already managed by `apt`, Snap, `file`, or
`git`.
- Public defaults and argument specifications contain only the seven variables
named in this roadmap.
- A caller may disable dependency management and select an existing Go
executable with `seriatim_go_binary`.
- Tasks requiring superuser access use task-level privilege escalation.
- Syntax checking, ansible-lint, a focused local convergence test, and a clean
repeated run pass.
- Role documentation describes the actual concise behavior and does not claim
transactional build safety or exhaustive corruption recovery.
- No repository other than `ansible-role-seriatim` and the workspace control
repository is modified.
## Dependencies and Follow-up Work
The role requires access to the Seriatim Git repository, Ubuntu Snap
infrastructure, and Go module sources from the managed host. After this revised
implementation is reviewed, its minimal conventions can inform a fresh Audita
roadmap and the remaining application roles.
The original implementation commits remain in Git history as evidence of the
superseded design. The prior completion and remediation documents must not be
used as templates for another role.
## Potential Future Hardening
- Build in a temporary location and validate before replacing the installed
executable.
- Verify release signatures or source checksums.
- Record compiler and build-input identity for exact rebuild invalidation.
- Detect arbitrary binary modification independently of reported version.
- Protect or recover from unexpected symbolic links and malformed managed
paths.
- Add broader Ubuntu release and architecture test coverage only if future
platform behavior warrants it.
These are candidates for separately selected features if operational
experience or a changed threat model justifies them.

View File

@@ -0,0 +1,250 @@
# Feature 0002: Audita Source Installation and Configuration
Status: done
## Summary
Provide a small, independently usable `rakestraw.audita` role that installs
Audita from a pinned Git tag, builds its executable on the managed host, and
offers an ergonomic field-specific interface for its versioned YAML
configuration. Unspecified optional fields are omitted so Audita retains
ownership of its application defaults.
## Problem or Opportunity
The completed source-installation flow is concise and correct, but the initial
configuration interface exposes only one `audita_config` mapping. That requires
every caller to know and reproduce Audita's native nested schema, and it does
not provide the ordinary role ergonomics expected for inventory variables.
The role should expose documented variables for individual settings and render
only values expressly selected by the caller. This permits straightforward
`host_vars`, `group_vars`, play variables, and suite-role overrides while
allowing upstream default changes to take effect automatically when a setting
is not managed by Ansible.
## Scope
- Retain the completed Ubuntu 26.04 `amd64` and `arm64` source installation.
- Retain default tag `v0.9.1`, Go Snap channel `1.26/stable`, source path
`/usr/local/src/audita`, and binary path `/usr/local/bin/audita`.
- Retain rebuild triggers of changed Git checkout or absent binary.
- Replace the complete `audita_config` mapping with typed, field-specific
configuration variables.
- Always render the required configuration schema version, defaulting to `1`.
- Define every optional configuration variable as `null` by default and omit
its YAML field when it remains null.
- Render nested YAML sections only when at least one setting in that section is
non-null.
- Manage `/usr/local/etc/audita/config.yml` from a Jinja template as
`root:root` mode `0644`.
- Keep defaults, argument specifications, template, README, metadata,
dependency declaration, and focused tests consistent with this contract.
## Non-goals
- Copying Audita's built-in values into role defaults or the default rendered
file.
- D&D-specific model selection, concurrency, thresholds, transcript context,
or other suite policy.
- A parallel mapping-based configuration escape hatch or merge/precedence
rules between two configuration interfaces.
- API keys or other secret values. Variables may select environment-variable
names, but the role does not manage their values.
- Creation of the `narratio` account or management of runtime, campaign,
glossary, transcript, diagnostics, or secret-delivery infrastructure.
- Services, scheduling, removal behavior, pipeline composition, prebuilt
artifacts, or cross-compilation.
- Production execution of Audita for build or configuration validation.
- Fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, compiler inspection, or out-of-band drift detection.
## Target End State
With no configuration overrides, the role writes the minimal valid document:
```yaml
version: 1
```
When a caller sets an optional role variable, the corresponding native Audita
field appears in the correct YAML section. Fields whose variables remain null
are absent, including their parent sections when no child is selected. Empty
lists, empty strings, zero, and other expressly supplied non-null values are
rendered rather than mistaken for omission and are left for Audita to validate.
Installation and configuration converge independently. A configuration-only
change does not rebuild the binary, and an immediate repeat reports no changes.
Repository-local tests validate managed configurations through Audita. The
current CLI has no native release-identity command, so the suite deliberately
does not substitute a raw source-commit proxy for version coverage.
## Repository Ownership
- `ansible-role-audita` owns installation, the public configuration interface,
template, metadata, README, and repository-local tests.
- `../audita` is the read-only authority for build, CLI, configuration schema,
and application-default contracts.
- `rakestraw-ansible` is a read-only style reference for field-specific role
variables and conditional templates; its historical values are not
authoritative defaults.
- `ansible-role-dnd-pipeline` will later own D&D-specific overrides supplied
through the standalone role variables.
- `ansible-workspace-dnd` owns this roadmap, the staged plan, and aggregate
status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- Tag `v0.9.1` resolves to
`a84941d68168a1ed9ea7423b6477ae8218be73f9` and retains the build contract
already implemented and validated through role commit `3a8c21f`.
- Audita's strict schema version is `1`; all other top-level fields are
optional and overlay application defaults.
- `audita_config_version` names the schema version so `audita_version` remains
unambiguously the selected application release.
- Optional variables are present in role defaults with YAML null values. This
documents the interface and enables argument validation without emitting
upstream defaults.
- Template conditions use `is not none`, not truthiness, so expressly supplied
falsey values are rendered.
- String and list values must be safely encoded as YAML values rather than
interpolated with hand-written quoting.
- A parent mapping is emitted only when at least one corresponding child value
is non-null.
- The role does not validate Audita's semantic constraints during production
convergence. Native validation remains integration-test behavior.
- Task-level `become: true`, `community.general` 13.3.0, and all existing
installation decisions remain unchanged.
## Fixed Public Interface
Retain these installation variables:
| Variable | Default |
| --- | --- |
| `audita_version` | `v0.9.1` |
| `audita_repository_url` | `https://gitea.maximumdirect.net/eric/audita.git` |
| `audita_source_dir` | `/usr/local/src/audita` |
| `audita_binary_path` | `/usr/local/bin/audita` |
| `audita_manage_build_dependencies` | `true` |
| `audita_go_snap_channel` | `1.26/stable` |
| `audita_go_binary` | `/snap/bin/go` |
| `audita_config_path` | `/usr/local/etc/audita/config.yml` |
Provide these configuration variables:
| Variable | Default | Native field |
| --- | --- | --- |
| `audita_config_version` | `1` | `version` |
| `audita_pipeline_modules` | `null` | `pipeline.modules` |
| `audita_output_schema` | `null` | `output.schema` |
| `audita_llm_proposal_base_url` | `null` | `llm.proposal.base_url` |
| `audita_llm_proposal_model` | `null` | `llm.proposal.model` |
| `audita_llm_proposal_api_key_env` | `null` | `llm.proposal.api_key_env` |
| `audita_llm_proposal_timeout` | `null` | `llm.proposal.timeout` |
| `audita_llm_proposal_max_retries` | `null` | `llm.proposal.max_retries` |
| `audita_llm_validation_base_url` | `null` | `llm.validation.base_url` |
| `audita_llm_validation_model` | `null` | `llm.validation.model` |
| `audita_llm_validation_api_key_env` | `null` | `llm.validation.api_key_env` |
| `audita_llm_validation_timeout` | `null` | `llm.validation.timeout` |
| `audita_llm_validation_max_retries` | `null` | `llm.validation.max_retries` |
| `audita_concurrency_total_llm` | `null` | `concurrency.total_llm` |
| `audita_concurrency_proposal_llm` | `null` | `concurrency.proposal_llm` |
| `audita_concurrency_validation_llm` | `null` | `concurrency.validation_llm` |
| `audita_chunking_target_sections` | `null` | `chunking.target_sections` |
| `audita_chunking_max_section_tokens` | `null` | `chunking.max_section_tokens` |
| `audita_chunking_min_section_tokens` | `null` | `chunking.min_section_tokens` |
| `audita_normalization_max_segment_gap` | `null` | `normalization.max_segment_gap` |
| `audita_normalization_ellipsis_gap` | `null` | `normalization.ellipsis_gap` |
| `audita_normalization_max_segment_duration` | `null` | `normalization.max_segment_duration` |
| `audita_normalization_max_segment_tokens` | `null` | `normalization.max_segment_tokens` |
| `audita_thresholds_glossary` | `null` | `thresholds.glossary` |
| `audita_thresholds_homophones` | `null` | `thresholds.homophones` |
| `audita_thresholds_spoken_word` | `null` | `thresholds.spoken_word` |
| `audita_thresholds_grammar` | `null` | `thresholds.grammar` |
| `audita_context_description` | `null` | `context.description` |
| `audita_diagnostics_work_dir` | `null` | `diagnostics.work_dir` |
| `audita_diagnostics_retention` | `null` | `diagnostics.retention` |
The argument specification types values according to the native field shape.
Duration-like fields accept strings or numeric seconds as supported by Audita;
do not narrow the application contract unnecessarily.
## Simplest Viable Implementation
Retain the existing nine-task installation flow. Make only these production
changes:
1. Replace `audita_config` in defaults and argument specifications with the
field-specific variables above.
2. Add `templates/config.yml.j2`, always rendering `version` and conditionally
rendering every optional field and necessary parent mapping.
3. Replace the final `ansible.builtin.copy` task with one
`ansible.builtin.template` task using the existing destination, ownership,
and mode.
Do not add configuration assembly facts, nested merge filters, validation
commands, preliminary file probes, or multiple configuration tasks. The
template is the direct expression of the selected configuration state.
## Rationale and Alternatives
Field-specific variables are the ordinary ergonomic interface for inventory
and composing roles. Nullable defaults make that interface discoverable and
typed without freezing a duplicate copy of Audita's application defaults into
Ansible. Conditional rendering also preserves the distinction between an
unset field and a caller intentionally supplying a falsey value.
Leaving variables entirely undefined would produce the same file but weaken
interface documentation and argument validation. Section-level dictionaries
would shorten the template but require callers to understand more of the
native nested schema. Retaining `audita_config` beside field variables would
require unneeded merge and precedence semantics. None is preferable to the
single field-specific interface.
## Acceptance Criteria
- All existing source-installation and platform acceptance criteria continue
to pass without production task-flow expansion.
- Defaults and argument specifications contain exactly the eight installation
variables and thirty configuration variables in the Fixed Public Interface.
- No `audita_config` compatibility variable remains.
- Default convergence writes a YAML mapping containing exactly `version: 1`.
- Every optional field is absent when its variable is null.
- Setting a representative value in every configuration section renders the
correct nested native fields and passes `audita config validate`.
- Explicit falsey non-null values are rendered rather than omitted; semantic
validity remains Audita's responsibility.
- Configuration changes run the template task but not the build task and
reach an unchanged immediate repeat.
- The installed configuration remains a regular file owned by `root:root`
with mode `0644`.
- Production tasks do not invoke Audita, inspect the existing configuration,
or construct intermediate configuration state.
- The README documents each variable, null-as-unmanaged behavior, safe secret
environment-variable naming, and the distinction between application and
suite defaults.
- Syntax checking, production-profile ansible-lint, complete integration
testing, native minimal and representative configuration validation, and
clean repeated runs pass.
- Only `ansible-role-audita` and the workspace control repository change.
## Dependencies and Follow-up Work
The existing Audita role through commit `3a8c21f` is the implementation
baseline. The managed host and test prerequisites are unchanged.
The configuration amendment was completed in `ansible-role-audita` commits
`e61f02f` and `847c4c3` and validated by its complete integration suite. The
proposed Notarius roadmap should use the same nullable field-specific approach
where appropriate.
## Potential Future Hardening
- Validate configuration during production convergence if later operating
requirements explicitly select that behavior.
- Manage secret environment delivery, diagnostics paths, runtime accounts, or
services as separate suite-level or application-level features.
- Detect source signatures, compiler drift, or out-of-band binary changes if
the threat model changes.

View File

@@ -0,0 +1,364 @@
# Feature 0003: Notarius Source Installation and Configuration
Status: done
## Summary
Provide a small, independently usable `rakestraw.notarius` role that installs
Notarius from a pinned Git tag, builds its executable on the managed host, and
manages its versioned YAML configuration. Reuse the established module-driven
application-role pattern while leaving D&D pipeline policy to the suite-level
role.
## Problem or Opportunity
At feature selection, the `ansible-role-notarius` repository contained only
its initial placeholder files. Notarius is one of the five required pipeline
applications and needed an independently usable installation and
native-configuration role before the suite role could compose it with
Seriatim, Audita, and the remaining applications.
Seriatim and Audita have established the preferred source-build architecture.
Notarius can use the same concise task flow, with only its native configuration
and build contract differing.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the role implementation,
its public configuration variables, and its template behavior.
- [The testing house style](../../testing.md) governs repository-local
validation. Tests exercise role-owned behavior through the public interface
without snapshotting current defaults, tracing task implementation, or
rechecking postconditions owned by trusted Ansible modules.
## Scope
- Implement `ansible-role-notarius` as a conventional standalone role.
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
- Install Git and the official Go Snap with classic confinement when build
dependency management is enabled.
- Default the Go Snap channel to `1.26/stable`.
- Check out immutable Notarius tag `v0.6.0` by default under the root-owned
path `/usr/local/src/notarius`.
- Build Notarius with its upstream release build contract and install the
native executable at `/usr/local/bin/notarius`.
- Rebuild when the Git checkout changes or the binary is absent.
- Converge the installed binary to `root:root` ownership and mode `0755`.
- Manage a versioned Notarius YAML configuration at
`/usr/local/etc/notarius/config.yml`, owned by `root:root` with mode `0644`.
- Default the managed configuration to the minimal valid mapping
`{"version": 4}`, allowing Notarius's built-in defaults to govern behavior.
- Expose native configuration through field-specific role variables. Give the
required schema version a concrete default and make every optional setting
nullable so omitted settings remain owned by Notarius.
- Keep defaults, argument specifications, README, metadata, dependency
declaration, and focused local tests consistent with this contract.
## Non-goals
- A D&D pipeline definition, module selection, LLM profile, concurrency
policy, output paths, cache policy, or other suite-specific configuration.
- A raw mapping for the complete configuration document, a template override,
or competing configuration interfaces.
- Role defaults copied from Notarius merely to reproduce the application's
built-in defaults in YAML.
- Decomposing the open-ended `pipelines` map into role variables for every
possible pipeline, step, lane, binding, validator, option, or reference.
- API keys, secret values, environment files, or another secret-delivery
mechanism.
- PromptKit profiles or other externally maintained prompt content.
- Creation or management of the `narratio` account, operator groups, campaign
data, runtime output, debug, cache, checkpoint, or transcript directories.
- Installation or configuration of another pipeline application.
- Services, scheduling, removal behavior, or pipeline composition.
- Prebuilt release artifacts or cross-compilation.
- Production execution of Notarius to validate the build or configuration.
- Detection of out-of-band binary modification, compiler changes, or fixed
build-command changes.
- Build fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, or special recovery for malformed or adversarial host state.
- A shared build helper role or dedicated platform-matrix infrastructure.
## Target End State
On an Ubuntu 26.04 `amd64` or `arm64` host, applying the role with defaults
installs or confirms Git and Go, checks out Notarius `v0.6.0` at
`/usr/local/src/notarius`, builds `/usr/local/bin/notarius`, and writes
`/usr/local/etc/notarius/config.yml`. Source and installed files have the
stated root ownership and permissions, and the configuration contains
`version: 4`.
When a caller sets an optional configuration variable, the corresponding
native field appears in the correct YAML section. Null fields are absent, as
are parent sections with no selected descendants. Explicit false, zero, empty
string, empty collection, and other non-null values are rendered and left to
Notarius's native validation. `notarius_pipelines` represents the native
open-ended `pipelines` field as one mapping rather than attempting to mirror
its extensible internal schema in Ansible variables. Callers may define
pipeline-map fragments in separate inventory files and compose them into the
final value with ordinary Ansible/Jinja expressions.
An immediate second application reports no changes. A changed Git checkout or
missing binary causes one build; configuration changes converge independently
through the ordinary `ansible.builtin.template` operation.
Repository-local tests exercise the real role through its public variables.
They use the default invocation only as a smoke test, explicitly select
immutable `v0.5.0` to prove version selection, exercise missing-binary recovery
with a caller-supplied Go executable, and render one representative
configuration covering null omission, intentional falsey values, and
caller-side pipeline composition. Application-native commands verify the
selected release and configuration validity, and immediate repeated
applications verify convergence.
## Repository Ownership
- `ansible-role-notarius` owns the role implementation, public interface,
configuration serialization, metadata, dependency declaration, README, and
repository-local validation.
- `../notarius` is the read-only authority for build, CLI, and configuration
contracts.
- `rakestraw-ansible` is a read-only style and deployment-policy reference.
- `ansible-role-dnd-pipeline` will later own the D&D-specific configuration
supplied through the standalone role's field-specific variables.
- `ansible-workspace-dnd` owns this roadmap, the eventual staged plan, and
aggregate status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- The selected release is tag `v0.6.0`, which resolves to commit
`77ae132e5609916da40dcd4fcc749c000a63cbac`.
- The release declares Go 1.25.5. The suite-standard Go Snap channel remains
`1.26/stable` and satisfies that requirement.
- The upstream release build uses package `./cmd/notarius`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flag
`-X gitea.maximumdirect.net/eric/notarius/internal/buildinfo.Override=<version>`.
- `notarius --version` prints `notarius <version>`. This is test evidence, not
an additional production rebuild trigger or post-build convergence task.
- Notarius configuration schema version 4 explicitly supports a document
containing only `version: 4`, with omitted values supplied by application
defaults.
- `notarius_config_version` names the schema version so `notarius_version`
remains unambiguously the selected application release.
- Optional configuration variables are declared with YAML null defaults.
Template conditions use `is not none`, and parent mappings are emitted only
when at least one descendant is non-null.
- The native `pipelines` field is exposed as the nullable
`notarius_pipelines` mapping. It is one field-specific variable, not a raw
mapping for the complete document; the role serializes its value without
defining a parallel schema for pipeline internals.
- Pipeline composition belongs to the caller. For example, inventory may
define `notarius_pipeline_group_one` and `notarius_pipeline_group_two` as
mappings and set `notarius_pipelines` to
`{{ notarius_pipeline_group_one | combine(notarius_pipeline_group_two) }}`.
The role accepts and renders the resulting mapping without its own merge or
precedence mechanism.
- Strings and mappings are serialized with Ansible or Jinja filters rather
than hand-written YAML quoting.
- `notarius config validate --config <path>` validates a managed configuration
without requiring a pipeline selection. It is used only by tests.
- Configuration discovery uses an explicit CLI path, then `NOTARIUS_CONFIG`,
then `/usr/local/etc/notarius/config.yml`; the role manages the installed
default path.
- Configuration contains no secrets by default. Consumers arrange any secret
environment variables outside this feature.
- Tasks that install dependencies or manage root-owned state use task-level
`become: true`.
- `community.general` supplies Snap management and is pinned to version
`13.3.0` in the role's collection requirements.
- Tag `v0.5.0` remains buildable with the same Go requirement, package, linker
symbol, and configuration schema and is the explicit immutable release used
for focused native version-selection coverage.
## Fixed Public Interface
Provide these installation variables:
| Variable | Default | Purpose |
| --- | --- | --- |
| `notarius_version` | `v0.6.0` | Git revision and release value supplied to the build |
| `notarius_repository_url` | `https://gitea.maximumdirect.net/eric/notarius.git` | Source repository |
| `notarius_source_dir` | `/usr/local/src/notarius` | Managed source checkout |
| `notarius_binary_path` | `/usr/local/bin/notarius` | Installed executable |
| `notarius_manage_build_dependencies` | `true` | Whether to install Git and Go |
| `notarius_go_snap_channel` | `1.26/stable` | Go Snap channel |
| `notarius_go_binary` | `/snap/bin/go` | Go executable used for the build |
| `notarius_config_path` | `/usr/local/etc/notarius/config.yml` | Managed configuration file |
Provide these configuration variables:
| Variable | Default | Native field |
| --- | --- | --- |
| `notarius_config_version` | `4` | `version` |
| `notarius_promptkit_profile_dir` | `null` | `promptkit.profile_dir` |
| `notarius_promptkit_profile_file` | `null` | `promptkit.profile_file` |
| `notarius_promptkit_local_backend_endpoint` | `null` | `promptkit.local_backend.endpoint` |
| `notarius_promptkit_local_backend_concurrency_limit` | `null` | `promptkit.local_backend.concurrency_limit` |
| `notarius_pipelines` | `null` | `pipelines` |
| `notarius_concurrency_total_llm` | `null` | `concurrency.total_llm` |
| `notarius_concurrency_stage_workers_extract` | `null` | `concurrency.stage_workers.extract` |
| `notarius_output_directory` | `null` | `output.directory` |
| `notarius_cache_chunk_plans_mode` | `null` | `cache.chunk_plans.mode` |
| `notarius_cache_chunk_plans_directory` | `null` | `cache.chunk_plans.directory` |
| `notarius_cache_checkpoints_enabled` | `null` | `cache.checkpoints.enabled` |
| `notarius_cache_checkpoints_directory` | `null` | `cache.checkpoints.directory` |
| `notarius_debug_directory` | `null` | `debug.directory` |
The package, build flags, linker symbol, environment values, file ownership,
and modes are fixed implementation details. The selected version is both the
Git revision and the value supplied to the upstream linker flag.
Argument specifications type each value according to its native shape. The
role does not reproduce semantic relationships such as the mutual exclusion
of PromptKit profile sources or the requirement for a local-backend endpoint;
Notarius owns those constraints. The `notarius_pipelines` value is a mapping
whose nested structure is governed by Notarius's versioned configuration
contract.
## Simplest Viable Implementation
The expected implementation is approximately nine ordinary tasks in one
readable task file:
1. Assert Ubuntu 26.04 and architecture `x86_64` or `aarch64`.
2. Install Git with `ansible.builtin.apt`, including
`cache_valid_time: 3600`, when dependency management is enabled.
3. Install the classic Go Snap from `notarius_go_snap_channel` with
`community.general.snap` when dependency management is enabled.
4. Create source, binary, and configuration parent directories with one
`ansible.builtin.file` loop.
5. Check out `notarius_version` with `ansible.builtin.git`, `force: true`, and
register the module result.
6. Inspect whether `notarius_binary_path` exists with
`ansible.builtin.stat`.
7. Run the upstream Go build through `notarius_go_binary` when the checkout
changed or the binary is absent.
8. Converge recursive source ownership and binary ownership and mode with one
item-driven `ansible.builtin.file` loop.
9. Render the field-specific configuration with one
`ansible.builtin.template` task, conditionally emitting optional fields and
parent sections at `notarius_config_path`.
Apply task-level privilege escalation only where required. Use `argv` for the
build command and put its two conditions directly on the build task. Do not
add a rebuild fact, handler, handler flush, executable discovery, compiler or
version interrogation, configuration assembly facts, preliminary
configuration probes, or post-operation validation to production tasks.
## Rationale and Alternatives
Notarius has the same installation mechanics as the completed Seriatim and
Audita roles: declarative dependency and checkout management surrounding one
imperative build command. Binary existence is the only state probe Ansible
needs because it controls whether that command must run.
Field-specific variables are the ordinary ergonomic interface for inventory
and composing roles. Nullable defaults expose and type that interface without
freezing Notarius's built-in defaults into Ansible. Conditional rendering
preserves the distinction between omission and an intentionally falsey value.
The pipeline definitions are the deliberate exception to leaf-level
variables. `pipelines` is itself an open-ended map whose nested keys depend on
registered modules and evolve with the application's native schema. Exposing
that native field as one nullable mapping keeps the interface practical while
still avoiding a raw complete-document mapping or merge semantics. The suite
role can later supply its maintained D&D pipeline through
`notarius_pipelines` and supply operating policy through the other variables.
This boundary also supports modular inventory. A consumer can keep one or
more pipeline mappings in separate `host_vars`, `group_vars`, or included
variable files and combine them when assigning `notarius_pipelines`. Because
the native value is a mapping keyed by pipeline ID, dictionary composition
uses Ansible's `combine` filter; list concatenation with `+` applies only to
list-valued data. The role receives the already composed native mapping and
does not need custom loading, merging, or precedence behavior.
Leaving optional variables undefined would produce the same minimal file but
would weaken interface documentation and argument validation. Section-level
dictionaries would be less ergonomic for ordinary inventory values. A raw
complete configuration mapping would force consumers to replace the required
version and unrelated sections together and would conflict with the workspace
convention of one field-specific interface.
Managing `/usr/local/etc/notarius/config.yml` follows the application's own
configuration discovery contract and aligns locally installed software with
its configuration.
## Acceptance Criteria
### Required Role Behavior
- The role rejects unsupported distributions, Ubuntu releases, and
architectures before modifying application state.
- On a supported host, the role installs the selected Notarius source release
with its upstream build contract. The default selection for this feature is
tag `v0.6.0`, resolving to commit
`77ae132e5609916da40dcd4fcc749c000a63cbac`.
- The role converges the source tree, binary, and configuration to the paths,
ownership, and modes defined above using the responsible Ansible modules.
- The default template renders the minimal valid configuration containing the
required schema version and leaves optional policy to Notarius.
- A non-null optional variable renders its corresponding native field. Null
values and parent sections without a selected descendant are omitted;
intentional falsey values are preserved.
- Independently defined inventory mappings can be combined into
`notarius_pipelines`, and the resulting pipeline IDs and definitions are
rendered without structural rewriting by the role.
- A changed checkout or missing binary causes the imperative build to run. An
immediate repeated application with unchanged inputs reports no changes.
- Dependency opt-out accepts a caller-supplied `notarius_go_binary`.
- Tasks requiring elevated access use task-level privilege escalation, so the
role does not require play-level escalation.
- Defaults, argument specifications, template behavior, and documentation
remain aligned with the public interface without introducing a parallel raw
configuration or template-override interface.
- Production tasks contain no role-private build state, redundant probes,
application self-tests, or other behavior outside the selected invariants.
- No repository other than `ansible-role-notarius` and the workspace control
repository is modified.
### Required Validation
- Syntax checking and production-profile ansible-lint pass.
- A default invocation provides a smoke test through the installed CLI and
native configuration validator, followed immediately by a role application
reporting no changes. The test does not assert that the role's current
default release or complete default document remains unchanged.
- A focused version-selection case explicitly requests immutable tag `v0.5.0`
and verifies that the installed CLI reports `notarius v0.5.0`.
- One recovery case removes the binary, disables dependency management,
supplies a caller-selected Go executable, confirms that executable is used,
and finishes with a clean repeated application.
- One representative configuration case verifies selected rendered values,
selected omissions, intentional falsey values, and caller-side composition
of two pipeline mappings. The native Notarius validator accepts the result,
and an immediate repeated application reports no changes.
- Tests do not assert task names or order, individual task results, exact
current defaults, complete configuration snapshots, public-variable counts,
trusted-module file or package postconditions, or an exhaustive negative
platform matrix.
## Dependencies and Follow-up Work
The managed host requires access to the Notarius Git repository, Ubuntu Snap
infrastructure, and Go module sources. Actual transcript processing also needs
a configured pipeline, input artifacts, PromptKit assets and endpoints, and
secret environment variables; those belong to consumers or later suite-level
work.
The role was implemented in `ansible-role-notarius` commits `287fc4a` and
`733a194`, then finalized by remediation commit `eb4f511`. Its complete
integration suite passes. The pipeline role can now supply its D&D definitions
through `notarius_pipelines` and select the other field-specific values.
## Potential Future Hardening
- Build into a temporary path before replacing the installed executable.
- Verify source signatures or release checksums.
- Detect compiler, build-command, or out-of-band binary changes.
- Validate configuration during production convergence.
- Manage a dedicated runtime account, secret environment, state paths,
service, or schedule if later operating requirements select them.
- Add broader Ubuntu release and architecture test coverage only if future
platform behavior warrants it.

View File

@@ -0,0 +1,335 @@
# Feature 0004: Scriptorium Source Installation and Configuration
Status: done
## Summary
Provide a small, independently usable `rakestraw.scriptorium` role that
installs Scriptorium from a pinned Git tag, builds its executable on the
managed host, and manages its native YAML configuration. Preserve
Scriptorium's usefulness inside and outside the D&D transcript pipeline by
keeping application configuration in the standalone role and leaving prompt
library content and suite policy to their eventual owners.
## Problem or Opportunity
The `ansible-role-scriptorium` repository contains only its initial README and
license. Scriptorium is one of the five applications required by the pipeline,
but it is also a generally useful Promptkit-based application with independent
consumers. It needs a complete standalone installation and configuration role
before the pipeline role can compose it without owning Scriptorium-specific
behavior.
The completed Seriatim, Audita, and Notarius roles establish the concise
source-build pattern. Scriptorium can reuse that pattern while exposing its own
configuration contract through field-specific, nullable variables.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the role implementation,
public configuration interface, and template.
- [The testing house style](../../testing.md) governs repository-local
validation. Tests exercise role-owned behavior through public inputs and
native application outcomes without snapshotting defaults, tracing tasks, or
rechecking trusted-module postconditions.
- [The MVP roadmap](../mvp.md) fixes the common source-build architecture,
supported platform, filesystem layout, and standalone-role boundary.
## Scope
- Implement `ansible-role-scriptorium` as a conventional standalone role.
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
- Install Git and the official Go Snap with classic confinement when build
dependency management is enabled.
- Default the Go Snap channel to `1.26/stable`.
- Check out immutable Scriptorium tag `v0.13.0` by default under
`/usr/local/src/scriptorium`.
- Build the native executable with Scriptorium's release build contract and
install it at `/usr/local/bin/scriptorium`.
- Rebuild when the Git checkout changes or the binary is absent.
- Converge the source tree to `root:root` ownership and the installed binary to
`root:root` ownership and mode `0755`.
- Manage `/usr/local/etc/scriptorium/config.yml` as `root:root` with mode
`0644` using one role-owned template.
- Render `{}` when no application settings are selected, allowing Scriptorium
to use its built-in defaults without copying them into Ansible.
- Expose every application configuration field through a field-specific role
variable. Default each field to null and omit it from the rendered document
until a caller supplies a non-null value.
- Expose the native open-ended `backends` mapping as one nullable variable and
serialize the caller's mapping without inventing a second backend schema or
merge mechanism.
- Keep defaults, argument specifications, README, metadata, collection
dependency declaration, template, and focused integration tests aligned with
this contract.
## Non-goals
- D&D-specific prompts, profiles, schemas, model choices, paths, or other
pipeline policy.
- Cloning, copying, or otherwise populating prompt, profile, or schema
libraries.
- A role-managed Scriptorium service, HTTP listener lifecycle, scheduler, or
persistent runtime account.
- A raw mapping for the complete configuration document, a template override,
or parallel configuration interfaces.
- Copying Scriptorium's documented built-in defaults into role defaults merely
to render them back into YAML.
- Decomposing the open-ended `backends` mapping into variables for each backend
ID or backend-specific option.
- Secret values, environment files, or another credential-delivery mechanism.
- Installation or configuration of Promptkit, another pipeline application,
or the complete D&D suite.
- Installation from Scriptorium's published binary artifacts, cross-compiling,
or supporting platforms outside the MVP.
- Production execution of Scriptorium to validate its binary or configuration.
- Detection of out-of-band binary modification, compiler changes, or fixed
build-command changes.
- Build fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, or special recovery for malformed or adversarial host state.
## Target End State
On a supported host, applying the role with defaults installs or confirms Git
and Go, checks out Scriptorium `v0.13.0` at
`/usr/local/src/scriptorium`, builds `/usr/local/bin/scriptorium`, and manages
`/usr/local/etc/scriptorium/config.yml`. The managed configuration is the empty
mapping `{}`, so Scriptorium retains ownership of all application defaults.
When a caller sets an optional configuration variable, the corresponding
native YAML field appears in the correct section. Null fields are absent, as
are parent mappings with no selected descendants. Explicit false, zero, empty
string, empty collection, and other non-null values are serialized rather than
silently omitted, leaving their native semantics to Scriptorium.
`scriptorium_backends` represents the complete native `backends` field as a
mapping keyed by backend ID; the role does not rewrite its nested definitions
or combine fragments. Callers and composing roles may construct the final
mapping with ordinary inventory and Jinja expressions.
Prompt, profile, and schema directories remain caller-provided application
inputs. The standalone role exposes their configuration paths but does not
populate them. A later pipeline feature will deploy the maintained prompt
library and pass its selected locations through this public interface.
An immediate repeated application reports no changes. A changed checkout or a
missing binary causes the build command to run. Configuration changes converge
through the template without becoming build triggers.
## Repository Ownership
- `ansible-role-scriptorium` owns the role implementation, public variables,
native configuration serialization, metadata, dependency declaration,
documentation, and repository-local tests.
- `../scriptorium` is the read-only authority for release, build, CLI, and
configuration contracts.
- `rakestraw-ansible` is a read-only style and historical deployment reference.
- `ansible-role-dnd-pipeline` will later own D&D-specific Scriptorium values and
prompt-library deployment through the standalone role's public interface.
- `ansible-workspace-dnd` owns this roadmap, the eventual staged implementation
plan, and aggregate status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- The selected default release is annotated tag `v0.13.0`, resolving to commit
`f33af205242cbaeeb689c179c0465bd10beaa1a3`.
- The release declares Go 1.25.5. The suite-standard `1.26/stable` Go Snap
channel satisfies that requirement.
- The native build uses package `./cmd/scriptorium`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags `-s -w`.
- Scriptorium does not embed the selected application tag and does not expose a
native application-version command. Production convergence does not add
version interrogation, and tests do not inspect the Git checkout merely to
manufacture version evidence.
- Scriptorium accepts an empty configuration and resolves all omitted settings
from built-in defaults. The role renders `{}` so the managed file is an
explicit YAML mapping while selecting no application policy.
- Configuration discovery checks `/usr/local/etc/scriptorium/config.yml`
before `/etc/scriptorium/config.yml`; the role manages the first path.
- Optional variables use YAML null defaults and template conditions use
`is not none`. Parent mappings are emitted only when at least one descendant
is non-null.
- Strings and mappings are serialized with Ansible or Jinja filters rather
than hand-written YAML quoting.
- `scriptorium_backends` is a native open-ended mapping. Caller-side mapping
composition is permitted, but the role supplies no merge or precedence
behavior.
- Backend configuration may name a credential environment variable through
`api_key_env`; secret values themselves remain outside the role and managed
file.
- Tasks installing dependencies or managing root-owned state use task-level
`become: true`.
- `community.general` supplies Snap management and is pinned to version
`13.3.0` in the role's collection requirements.
## Fixed Public Interface
Provide these installation variables:
| Variable | Default | Purpose |
| --- | --- | --- |
| `scriptorium_version` | `v0.13.0` | Selected Git revision |
| `scriptorium_repository_url` | `https://gitea.maximumdirect.net/eric/scriptorium.git` | Source repository |
| `scriptorium_source_dir` | `/usr/local/src/scriptorium` | Managed source checkout |
| `scriptorium_binary_path` | `/usr/local/bin/scriptorium` | Installed executable |
| `scriptorium_manage_build_dependencies` | `true` | Whether to install Git and Go |
| `scriptorium_go_snap_channel` | `1.26/stable` | Go Snap channel |
| `scriptorium_go_binary` | `/snap/bin/go` | Go executable used for the build |
| `scriptorium_config_path` | `/usr/local/etc/scriptorium/config.yml` | Managed configuration file |
Provide these nullable configuration variables:
| Variable | Native field |
| --- | --- |
| `scriptorium_prompt_dir` | `prompt_dir` |
| `scriptorium_profile_dir` | `profile_dir` |
| `scriptorium_schema_dir` | `schema_dir` |
| `scriptorium_server_addr` | `server.addr` |
| `scriptorium_server_artifact_root` | `server.artifact_root` |
| `scriptorium_server_max_request_bytes` | `server.max_request_bytes` |
| `scriptorium_server_max_artifact_bytes` | `server.max_artifact_bytes` |
| `scriptorium_server_max_response_bytes` | `server.max_response_bytes` |
| `scriptorium_defaults_render_format` | `defaults.render_format` |
| `scriptorium_backends` | `backends` |
Argument specifications type paths and strings according to their native
shape, the three server limits as integers, and `scriptorium_backends` as a
mapping. They do not reproduce semantic validation owned by Scriptorium. The
role preserves non-null values while the application decides whether a
selected value is valid or effective.
## Simplest Viable Implementation
The expected production implementation is approximately nine ordinary tasks
in one readable task file:
1. Assert Ubuntu 26.04 and architecture `x86_64` or `aarch64`.
2. Install Git with `ansible.builtin.apt`, including
`cache_valid_time: 3600`, when dependency management is enabled.
3. Install the classic Go Snap from `scriptorium_go_snap_channel` with
`community.general.snap` when dependency management is enabled.
4. Create the source, binary, and configuration parent directories with one
`ansible.builtin.file` loop.
5. Check out `scriptorium_version` with `ansible.builtin.git`, `force: true`,
and register the module result.
6. Inspect whether `scriptorium_binary_path` exists with
`ansible.builtin.stat`.
7. Run the native Go build through `scriptorium_go_binary` when the checkout
changed or the binary is absent.
8. Converge recursive source ownership and binary ownership and mode with one
item-driven `ansible.builtin.file` loop.
9. Render the field-specific configuration with one
`ansible.builtin.template` task.
Use `argv` for the build command, declare its change semantics, and put its two
conditions directly on the task. Do not add a rebuild fact, handler, executable
discovery, compiler or application interrogation, configuration assembly facts,
preliminary configuration probes, or post-operation validation to production
tasks.
## Rationale and Alternatives
A standalone role is valuable beyond the D&D pipeline and prevents the suite
role from becoming the owner of Scriptorium's native application interface.
The suite can later provide opinionated directory paths and backend choices
without reducing the role's usefulness to independent consumers.
Field-specific nullable variables preserve a documented and typed inventory
interface while allowing upstream defaults to evolve. Rendering `{}` is
preferable to copying those defaults into Ansible and is more explicit than an
empty file. Conditional sections distinguish omission from intentional falsey
values.
The `backends` mapping is the deliberate exception to leaf-level variables.
Its keys are caller-defined backend IDs and its values follow an extensible
native schema. Passing that one native field through as a mapping is simpler
and more useful than inventing variables for arbitrary IDs, while still
avoiding a raw mapping for the complete configuration document.
The role exposes server configuration because it is part of Scriptorium's
native interface, but it does not infer that callers want a managed service.
Consumers may invoke the CLI directly or arrange their own process lifecycle.
Scriptorium now publishes binary release artifacts, but the MVP deliberately
uses the common source-build model across all five applications. Artifact-based
installation remains a later cross-suite decision.
## Acceptance Criteria
### Required Role Behavior
- The role rejects unsupported platforms before modifying application state.
- On a supported host, it installs the selected Scriptorium source release and
builds the binary with the upstream release contract.
- Source, binary, and configuration state converge to the paths, ownership,
and modes selected above through the responsible Ansible modules.
- With no configuration variables selected, the template renders `{}` and
Scriptorium accepts the managed file while retaining its built-in defaults.
- Each non-null configuration variable renders its corresponding native field.
Null fields and empty parent sections are omitted, while intentional falsey
values are retained.
- A caller-supplied backend mapping is rendered without structural rewriting,
and independently defined mappings can be composed before assignment.
- A changed checkout or missing binary causes the imperative build to run. An
immediate repeated application with unchanged inputs reports no changes.
- Dependency opt-out accepts a caller-supplied `scriptorium_go_binary`.
- Root-owned operations use task-level privilege escalation; play-level
escalation is not required.
- Defaults, argument specifications, template behavior, README, and metadata
remain aligned with the public interface.
- Production tasks contain no role-private state, redundant probes,
application self-tests, or speculative guarantees.
- No repository other than `ansible-role-scriptorium` and the workspace control
repository is modified.
### Required Validation
- Syntax checking and production-profile ansible-lint pass.
- A default invocation exercises the installed application with the managed
configuration, followed immediately by a role application reporting no
changes. It does not snapshot the role's current default tag or complete
default document.
- One recovery case removes the binary, disables dependency management,
supplies a caller-selected Go executable, confirms that executable is used,
and finishes with a clean repeated application.
- One representative configuration case verifies selected scalar and nested
values, selected omissions, intentional zero values, and a caller-supplied
backend mapping. An offline native Scriptorium command accepts and uses the
managed configuration, and an immediate repeated application reports no
changes.
- Tests do not assert task names or order, individual task results, exact
current defaults, complete configuration snapshots, public-variable counts,
trusted-module file or package postconditions, or an exhaustive negative
platform matrix.
- Because Scriptorium exposes no native application release identity, the test
suite does not substitute a Git-checkout assertion or version-specific
behavior snapshot for a native version-selection test.
## Dependencies and Follow-up Work
The managed host requires access to the Scriptorium Git repository, Ubuntu
Snap infrastructure, and Go module sources. Useful prompt execution also needs
prompt definitions and, depending on the chosen configuration, profiles,
schemas, backend endpoints, and credential environment variables. Those inputs
remain caller responsibilities for this standalone feature.
With this feature complete, the Narratio standalone role can be designed
against all four downstream application-role interfaces. The later pipeline
role will install maintained prompt-library content and supply D&D-specific
Scriptorium configuration through this role.
The role was implemented in `ansible-role-scriptorium` commits `90d7f45` and
`5944eac`, then finalized after independent review by remediation commit
`8f47aa8`. Its complete integration suite passes.
## Potential Future Hardening
- Build into a temporary path before replacing the installed executable.
- Verify source signatures or release artifacts.
- Detect compiler, build-command, or out-of-band binary changes.
- Validate configuration during production convergence.
- Manage a service, runtime account, secret environment, or network controls if
later operating requirements select them.
- Support Scriptorium's published binary artifacts as part of a future
suite-wide installation-model change.
- Add broader platform coverage only when supported-platform behavior expands.

View File

@@ -0,0 +1,465 @@
# Feature 0005: Narratio Source Installation and Configuration
Status: done
## Summary
Provide a small, independently usable `rakestraw.narratio` role that installs
Narratio from a pinned Git tag, builds its executable on the managed host,
creates the application account and runtime directories, and manages its
native pipeline configuration. Keep the role application-specific so the
later suite role can supply D&D policy through its public interface without
making the Narratio role responsible for the other applications or campaign
content.
## Problem or Opportunity
The `ansible-role-narratio` repository contains only its initial README and
license. Narratio is the command-line orchestrator for the transcript pipeline,
so the complete suite cannot be composed until Narratio has an independently
usable installation and configuration role.
The four completed downstream application roles establish the concise
source-build pattern. Narratio can reuse that pattern, but its native contract
also requires a deployment account, shared writable runtime areas, a campaign
registry root, and a substantially larger pipeline configuration interface.
This feature fixes those boundaries before suite composition begins.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the role implementation,
public configuration interface, and template.
- [The testing house style](../../testing.md) governs repository-local
validation. Tests exercise role-owned behavior through public inputs and
native application outcomes without snapshotting defaults, tracing tasks, or
rechecking trusted-module postconditions.
- [The MVP roadmap](../mvp.md) fixes the common source-build architecture,
supported platform, filesystem layout, and standalone-role boundary.
## Scope
- Implement `ansible-role-narratio` as a conventional standalone role.
- Support Ubuntu 26.04 on native `amd64` and `arm64` hosts.
- Install Git and the official Go Snap with classic confinement when build
dependency management is enabled.
- Default the Go Snap channel to `1.26/stable`.
- Check out immutable Narratio tag `v2.0.0` by default under
`/usr/local/src/narratio`.
- Build the native executable with Narratio's release build contract and
install it at `/usr/local/bin/narratio`.
- Rebuild when the Git checkout changes or the binary is absent.
- Converge the source tree and installed binary to root ownership, with the
binary at mode `0755`.
- Create the `narratio` system group and system account with
`/var/lib/narratio` as its home and a non-login shell.
- Create the workspace, spool, and cache roots as group-writable,
setgid directories owned by `narratio:narratio`.
- Create the campaign registry as a root-managed, operator-readable content
root; leave its contents to the suite role or another caller.
- Manage `/usr/local/etc/narratio/pipeline.yml` as `root:narratio` with mode
`0640` using one role-owned template.
- Require the caller to supply the deployment-specific WhisperX transcription
URL because Narratio has no valid universal value for this required field.
- Give filesystem roots concrete role-owned defaults. Default other optional
application settings to null and omit them until a caller supplies a
non-null value, allowing Narratio to retain ownership of its built-in
defaults.
- Expose scalar fields individually. Expose native open-ended collections as
one variable each, including publish outputs, Notarius references and
outputs, and Scriptorium artifacts and artifact families.
- Permit callers to compose those collection variables in inventory before
assigning the final value; do not add role-owned merge or precedence logic.
- Expose ConfigKit's explicit import list in the root document without taking
ownership of the imported fragments or named profile overlays.
- Keep defaults, argument specifications, README, metadata, collection
dependency declaration, template, and focused integration tests aligned
with this contract.
## Non-goals
- Installing or configuring Audita, Notarius, Seriatim, Scriptorium, WhisperX,
or the complete D&D suite.
- Populating campaign data, prompt libraries, profiles, schemas, or session
documents.
- Selecting D&D-specific pipelines, campaigns, models, prompts, artifacts,
extraction lanes, publish rules, storage providers, or application paths.
- Managing ConfigKit import fragments or named profile overlay files.
- Managing credentials, secret values, a secrets directory, environment
injection, or the pipeline-wide secret-delivery policy.
- Adding human operator accounts to the `narratio` group; the suite role owns
operator selection and membership.
- A Narratio daemon, service unit, scheduler, or timer.
- A raw mapping for the complete pipeline document, a template override, or a
second parallel configuration interface.
- Copying Narratio's built-in defaults into role defaults merely to render
them back into YAML.
- Decomposing open-ended artifact, artifact-family, reference, or output maps
into variables for caller-defined keys.
- Installing from published binary artifacts, cross-compiling, or supporting
platforms outside the MVP.
- Production execution of Narratio to validate its binary or configuration.
- Detection of out-of-band binary modification, compiler changes, or fixed
build-command changes.
- Build fingerprints, checksums, sidecar state, staged replacement, manual Git
cleanup, or special recovery for malformed or adversarial host state.
## Target End State
On a supported host, applying the role with the required
`narratio_whisperx_transcribe_url` installs or confirms Git and Go, creates the
Narratio account and filesystem roots, checks out Narratio `v2.0.0` at
`/usr/local/src/narratio`, builds `/usr/local/bin/narratio`, and manages
`/usr/local/etc/narratio/pipeline.yml`.
The baseline managed pipeline document contains only the caller's required
WhisperX URL and the filesystem roots the role deliberately owns. Narratio
continues to supply all other application defaults. When a caller sets an
optional configuration variable, the corresponding native YAML field appears
in the correct section. Null fields and parent mappings with no selected
descendants are absent. Explicit false, zero, empty string, empty list, empty
mapping, and other non-null values are serialized rather than silently
omitted, leaving their native semantics to Narratio.
Native open-ended collections pass through without structural rewriting.
Callers and composing roles may define fragments in separate inventory files
and combine them with ordinary Ansible/Jinja expressions before assigning the
final collection variable. The role does not merge fragments or define
precedence among them.
The `narratio` account owns the mutable workspace, spool, and cache roots.
Their setgid group-write permissions support later direct invocation by human
operators whom the suite role adds to the `narratio` group. The root-managed
campaign registry remains readable but not writable by those operators.
An immediate repeated application reports no changes. A changed checkout or a
missing binary causes the build command to run. Account, directory, and
configuration changes converge through their responsible Ansible modules and
do not become build triggers.
## Repository Ownership
- `ansible-role-narratio` owns the role implementation, application account,
runtime and campaign-root state, public variables, native root pipeline
serialization, metadata, dependency declaration, documentation, and
repository-local tests.
- `../narratio` is the read-only authority for release, build, CLI,
configuration, filesystem, and integration contracts.
- `rakestraw-ansible` is a read-only style and historical deployment reference.
- `ansible-role-dnd-pipeline` will later own compatible application versions,
D&D-specific Narratio values, campaign and prompt content, secret delivery,
and human operator membership through the standalone roles' public
interfaces.
- `ansible-workspace-dnd` owns this roadmap, the eventual staged implementation
plan, and aggregate status.
- All other repositories remain unchanged.
## Constraints and Settled Decisions
- The selected default release is lightweight tag `v2.0.0`, resolving to
commit `ed4623bc415901134c765fe9cf06d59aa7891500`.
- The release declares Go 1.26.0. The suite-standard `1.26/stable` Go Snap
channel satisfies that requirement.
- The native build uses package `./cmd/narratio`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags
`-s -w -X gitea.maximumdirect.net/eric/narratio/internal/buildinfo.Version=<version>`.
- `narratio version` reports the embedded selected tag and provides the native
observable for an explicitly requested version in integration tests.
- Narratio discovers `/usr/local/etc/narratio/pipeline.yml` before
`/etc/narratio/pipeline.yml`; the role manages the first path by default.
- `whisperx.transcribe_url` is the only pipeline field without an application
default that is required for pipeline validation. The role therefore exposes
`narratio_whisperx_transcribe_url` as a required public input rather than
inventing a deployment endpoint.
- Workspace, campaign, spool, and cache roots are concrete role defaults
because the role creates and owns the corresponding filesystem state. These
are intentional deployment policy, not a duplicate database of application
defaults.
- All other optional configuration variables use YAML null defaults and
template conditions use `is not none`. Parent mappings are emitted only
when at least one descendant is non-null.
- Strings and collections are serialized with Ansible or Jinja filters rather
than hand-written YAML quoting.
- `narratio_publish_outputs`, `narratio_notarius_references`,
`narratio_notarius_outputs`, `narratio_scriptorium_artifacts`, and
`narratio_scriptorium_artifact_families` represent their complete native
fields. Caller-side composition is permitted, but the role supplies no merge
behavior.
- Credential configuration contains environment-variable names only. Secret
values remain outside the role and managed pipeline document.
- The configuration directory is `root:narratio` mode `0750`; the pipeline
file is `root:narratio` mode `0640`.
- Mutable runtime roots are `narratio:narratio` mode `2775`. The campaign root
is `root:narratio` mode `0755` because version-controlled content is
populated by a separate owner and is not operator-edited on the host.
- Tasks installing dependencies or managing privileged state use task-level
`become: true`.
- `community.general` supplies Snap management and is pinned to version
`13.3.0` in the role's collection requirements.
## Fixed Public Interface
### Installation and Managed Filesystem
| Variable | Default | Purpose |
| --- | --- | --- |
| `narratio_version` | `v2.0.0` | Selected Git revision and embedded build version |
| `narratio_repository_url` | `https://gitea.maximumdirect.net/eric/narratio.git` | Source repository |
| `narratio_source_dir` | `/usr/local/src/narratio` | Managed source checkout |
| `narratio_binary_path` | `/usr/local/bin/narratio` | Installed executable |
| `narratio_manage_build_dependencies` | `true` | Whether to install Git and Go |
| `narratio_go_snap_channel` | `1.26/stable` | Go Snap channel |
| `narratio_go_binary` | `/snap/bin/go` | Go executable used for the build |
| `narratio_user` | `narratio` | System account owning mutable runtime state |
| `narratio_group` | `narratio` | System group sharing mutable runtime state |
| `narratio_config_path` | `/usr/local/etc/narratio/pipeline.yml` | Managed root pipeline document |
| `narratio_workspace_root` | `/var/lib/narratio` | Managed workspace root and account home |
| `narratio_campaigns_root` | `/usr/local/share/narratio/campaigns` | Managed campaign registry root |
| `narratio_spool_root` | `/var/spool/narratio` | Managed spool root |
| `narratio_cache_root` | `/var/cache/narratio` | Managed cache root |
Changing a managed root changes both its rendered pipeline value and the
directory the role manages. The role does not infer additional arbitrary paths
embedded inside caller-supplied open-ended collections.
### Pipeline Structure and Storage
Except where a default is shown, every variable below defaults to null and is
omitted when null.
| Variable | Default | Native field |
| --- | --- | --- |
| `narratio_configkit_imports` | `null` | `configkit.imports` |
| `narratio_workspace_cleanup_after_publish` | `null` | `workspace.cleanup_after_publish` |
| `narratio_campaigns_default_campaign_id` | `null` | `campaigns.default_campaign_id` |
| `narratio_storage_backend` | `null` | `storage.backend` |
| `narratio_storage_s3_bucket` | `null` | `storage.s3.bucket` |
| `narratio_storage_s3_root_prefix` | `null` | `storage.s3.root_prefix` |
| `narratio_storage_s3_region` | `null` | `storage.s3.region` |
| `narratio_storage_s3_endpoint` | `null` | `storage.s3.endpoint` |
| `narratio_storage_s3_force_path_style` | `null` | `storage.s3.force_path_style` |
| `narratio_storage_s3_access_key_id` | `null` | `storage.s3.access_key_id` environment-variable name |
| `narratio_storage_s3_secret_access_key` | `null` | `storage.s3.secret_access_key` environment-variable name |
| `narratio_spool_delete_audio_after_publish` | `null` | `spool.delete_audio_after_publish` |
| `narratio_cache_s3_audio` | `null` | `cache.s3_audio` |
| `narratio_publish_enabled` | `null` | `publish.enabled` |
| `narratio_publish_upload_run` | `null` | `publish.upload_run` |
| `narratio_publish_outputs` | `null` | Complete native `publish.outputs` list |
### WhisperX, Seriatim, and Audita
| Variable | Default | Native field |
| --- | --- | --- |
| `narratio_whisperx_transcribe_url` | required | `whisperx.transcribe_url` |
| `narratio_whisperx_language` | `null` | `whisperx.language` |
| `narratio_whisperx_timeout` | `null` | `whisperx.timeout` |
| `narratio_whisperx_retries` | `null` | `whisperx.retries` |
| `narratio_whisperx_retry_delay` | `null` | `whisperx.retry_delay` |
| `narratio_whisperx_concurrency` | `null` | `whisperx.concurrency` |
| `narratio_seriatim_binary` | `null` | `seriatim.binary` |
| `narratio_seriatim_timeout` | `null` | `seriatim.timeout` |
| `narratio_seriatim_output_schema` | `null` | `seriatim.output_schema` |
| `narratio_seriatim_coalesce_gap` | `null` | `seriatim.coalesce_gap` |
| `narratio_seriatim_report` | `null` | `seriatim.report` |
| `narratio_seriatim_env_overlap_word_run_gap` | `null` | `seriatim.env.overlap_word_run_gap` |
| `narratio_seriatim_env_overlap_word_run_reorder_window` | `null` | `seriatim.env.overlap_word_run_reorder_window` |
| `narratio_seriatim_env_backchannel_max_duration` | `null` | `seriatim.env.backchannel_max_duration` |
| `narratio_seriatim_env_filler_max_duration` | `null` | `seriatim.env.filler_max_duration` |
| `narratio_audita_binary` | `null` | `audita.binary` |
| `narratio_audita_timeout` | `null` | `audita.timeout` |
| `narratio_audita_llm_api_key` | `null` | `audita.llm_api_key` environment-variable name |
| `narratio_audita_modules` | `null` | `audita.modules` |
| `narratio_audita_base_url` | `null` | `audita.base_url` |
| `narratio_audita_model` | `null` | `audita.model` |
| `narratio_audita_total_llm_concurrency` | `null` | `audita.total_llm_concurrency` |
| `narratio_audita_proposal_llm_concurrency` | `null` | `audita.proposal_llm_concurrency` |
| `narratio_audita_validation_model` | `null` | `audita.validation_model` |
| `narratio_audita_validation_llm_concurrency` | `null` | `audita.validation_llm_concurrency` |
| `narratio_audita_transcript_description` | `null` | `audita.transcript_description` |
| `narratio_audita_config_path` | `null` | `audita.config_path` |
| `narratio_audita_output_schema` | `null` | `audita.output_schema` |
| `narratio_audita_work_dir_retention` | `null` | `audita.work_dir_retention` |
| `narratio_audita_report` | `null` | `audita.report` |
### Transcript Stages and Rendering
| Variable | Default | Native field |
| --- | --- | --- |
| `narratio_normalize_output_path` | `null` | `normalize.output_path` |
| `narratio_normalize_output_schema` | `null` | `normalize.output_schema` |
| `narratio_normalize_report` | `null` | `normalize.report` |
| `narratio_trim_enabled` | `null` | `trim.enabled` |
| `narratio_trim_output_path` | `null` | `trim.output_path` |
| `narratio_trim_bounds_prompt_id` | `null` | `trim.bounds.prompt_id` |
| `narratio_trim_bounds_profile_id` | `null` | `trim.bounds.profile_id` |
| `narratio_trim_bounds_transcript_input_name` | `null` | `trim.bounds.transcript_input_name` |
| `narratio_trim_bounds_output_path` | `null` | `trim.bounds.output_path` |
| `narratio_trim_bounds_timeout` | `null` | `trim.bounds.timeout` |
| `narratio_trim_bounds_render_debug` | `null` | `trim.bounds.render_debug` |
| `narratio_trim_bounds_render_output_path` | `null` | `trim.bounds.render_output_path` |
| `narratio_trim_seriatim_report` | `null` | `trim.seriatim.report` |
| `narratio_render_enabled` | `null` | `render.enabled` |
| `narratio_render_format` | `null` | `render.format` |
| `narratio_render_title` | `null` | `render.title` |
| `narratio_render_include_timestamps` | `null` | `render.include_timestamps` |
| `narratio_render_include_segment_ids` | `null` | `render.include_segment_ids` |
| `narratio_render_include_metadata` | `null` | `render.include_metadata` |
### Scriptorium, Notarius, and Notification
| Variable | Default | Native field |
| --- | --- | --- |
| `narratio_scriptorium_binary` | `null` | `scriptorium.binary` |
| `narratio_scriptorium_config_path` | `null` | `scriptorium.config_path` |
| `narratio_scriptorium_timeout` | `null` | `scriptorium.timeout` |
| `narratio_scriptorium_render_debug` | `null` | `scriptorium.render_debug` |
| `narratio_scriptorium_artifacts` | `null` | Complete native `scriptorium.artifacts` map |
| `narratio_scriptorium_artifact_families` | `null` | Complete native `scriptorium.artifact_families` map |
| `narratio_notarius_enabled` | `null` | `notarius.enabled` |
| `narratio_notarius_binary` | `null` | `notarius.binary` |
| `narratio_notarius_config_path` | `null` | `notarius.config_path` |
| `narratio_notarius_pipeline_id` | `null` | `notarius.pipeline_id` |
| `narratio_notarius_timeout` | `null` | `notarius.timeout` |
| `narratio_notarius_working_directory` | `null` | `notarius.working_directory` |
| `narratio_notarius_references` | `null` | Complete native `notarius.references` map |
| `narratio_notarius_outputs` | `null` | Complete native `notarius.outputs` map |
| `narratio_notification_mode` | `null` | `notification.mode` |
## Simplest Viable Implementation
The production task flow is:
1. Assert the supported platform and architecture.
2. Install Git and Go when dependency management is enabled.
3. Create the Narratio system group and account.
4. Create the source and configuration parent directories.
5. Create the mutable runtime roots and read-only campaign registry root.
6. Check out the selected Narratio revision with `ansible.builtin.git`.
7. Inspect only whether the installed binary exists, because that result is
needed to decide whether the imperative build command must run.
8. Build directly to the selected binary path when the checkout changed or
the binary is absent.
9. Converge binary ownership and mode with `ansible.builtin.file`.
10. Render the root pipeline document with one
`ansible.builtin.template` task.
The build command uses `narratio_go_binary` and runs only under the two stated
conditions. Ordinary modules own all other state checks. No role-private state,
pre-build version interrogation, post-build validation, configuration
validation, or redundant filesystem inspection belongs in production tasks.
The template is necessarily larger than those of the downstream roles because
Narratio's native pipeline schema is larger. Its logic remains mechanical:
serialize the required URL and role-owned roots, test each optional field with
`is not none`, emit a parent section only when needed, and pass native
collections through unchanged.
## Rationale and Alternatives
Narratio's configuration is broad, but a field-specific interface preserves
discoverability, argument validation, stable inventory names, and a clean
composition boundary for the suite role. A raw complete-document variable
would make the template shorter but would discard those benefits and conflict
with the established configuration policy. Open-ended native collections are
kept whole because decomposing caller-defined keys would create a second schema
and make inventory composition harder.
Requiring the WhisperX URL is preferable to installing a configuration that
Narratio cannot validate or inventing an endpoint that might silently direct
work to the wrong service. The baseline integration invocation supplies a
non-contacted test URL; production callers supply their actual endpoint.
The standalone role creates the application account and directory permissions
because those are Narratio runtime requirements. It does not select human
operators, because membership is deployment-wide policy and belongs in the
suite role.
ConfigKit imports and profiles remain available to advanced callers, but the
role manages only the canonical root document. This avoids a parallel raw-file
deployment subsystem. A caller that selects imports or profiles is responsible
for installing those additional files by another role or play.
## Acceptance Criteria
### Required Role Behavior
- The role rejects unsupported platforms before modifying application state.
- On a supported host, it installs the selected Narratio source release and
builds the binary with the upstream release contract.
- The system account, source, binary, configuration, runtime roots, and
campaign root converge to the paths, ownership, and modes selected above
through the responsible Ansible modules.
- With only `narratio_whisperx_transcribe_url` supplied, the rendered pipeline
contains that URL and the four role-owned roots, omits unselected optional
policy, and is accepted by Narratio's native configuration validator.
- Each non-null configuration variable renders its corresponding native field.
Null fields and empty parent sections are omitted, while intentional falsey
values are retained.
- Caller-supplied open-ended collections are rendered without structural
rewriting, and independently defined values can be composed before
assignment.
- A changed checkout or missing binary causes the imperative build to run. An
immediate repeated application with unchanged inputs reports no changes.
- Dependency opt-out accepts a caller-supplied `narratio_go_binary`.
- Root-owned operations use task-level privilege escalation; play-level
escalation is not required.
- Defaults, argument specifications, template behavior, README, and metadata
remain aligned with the public interface.
- Production tasks contain no role-private state, redundant probes,
application self-tests, or speculative guarantees.
- No repository other than `ansible-role-narratio` and the workspace control
repository is modified.
### Required Validation
- Syntax checking and production-profile ansible-lint pass.
- A baseline invocation supplies only the required WhisperX URL, exercises the
installed application by validating the managed pipeline as the Narratio
account, and is followed immediately by a role application reporting no
changes. It does not snapshot the role's current default tag or complete
default document.
- One explicitly selected-version case requests `v2.0.0` and verifies that
`narratio version` reports `v2.0.0`. The assertion proves caller-controlled
version selection, not that `v2.0.0` remains the role default.
- One recovery case removes the binary, disables dependency management,
supplies a caller-selected Go executable, confirms that executable is used,
and finishes with a clean repeated application.
- One representative configuration case verifies selected scalar and nested
values, selected omissions, intentional falsey values, and composed
open-ended collections. Narratio's native `config validate` accepts the
managed pipeline, and an immediate repeated application reports no changes.
- Tests do not assert task names or order, individual task results, exact
current defaults, complete configuration snapshots, public-variable counts,
trusted-module account, directory, file, package, checkout, or template
postconditions, or an exhaustive negative platform matrix.
## Dependencies and Follow-up Work
The managed host requires access to the Narratio Git repository, Ubuntu Snap
infrastructure, and Go module sources. Useful pipeline execution also requires
a reachable WhisperX service, the four downstream application binaries and
their configuration, campaign and session inputs, prompt content, and any
selected object-storage or model credentials. Those remain caller
responsibilities for this standalone feature.
With this feature complete, all five standalone application roles have stable
public interfaces. The next unit can design the suite-level pipeline role,
including dependency composition, compatible version selection, D&D pipeline
policy, campaign and prompt deployment, secrets, and operator group membership.
The role was implemented in `ansible-role-narratio` commits `3be78d8` and
`0e8ad9f`, then finalized after independent review by remediation commit
`7feff47`. Its complete integration suite passes.
## Potential Future Hardening
- Build into a temporary path before replacing the installed executable.
- Verify source signatures or release artifacts.
- Detect compiler, build-command, or out-of-band binary changes.
- Validate configuration during production convergence.
- Manage imported fragments or profile overlays if a concrete standalone-role
use case requires them.
- Add a scheduler, service, or non-interactive execution environment if later
operating requirements select one.
- Support Narratio's published binary artifacts as part of a future suite-wide
installation-model change.
- Add broader platform coverage only when supported-platform behavior expands.

View File

@@ -0,0 +1,388 @@
# Feature 0006: Pipeline Role Composition Foundation
Status: done
## Summary
Establish `ansible-role-dnd-pipeline` as the independently developed
suite-level role that composes the five completed application roles. The
feature provides a reproducible dependency manifest, a small suite-owned
public interface, compatible application-version selection, and the native
cross-application paths Narratio needs to find the installed tools.
This is the foundation of the complete D&D deployment, not the complete
deployment itself. Campaign data, the prompt library, operator access, secret
delivery, and opinionated D&D processing policy remain later pipeline-role
features.
## Problem or Opportunity
The five standalone application roles are implemented, tested, and
independently usable. The `ansible-role-dnd-pipeline` repository still contains
only its initial README and license, so consumers must currently discover,
install, version, and invoke every role separately and manually connect their
paths.
The suite needs one composition boundary before it can add D&D-specific
content and policy. Establishing that boundary first keeps later work focused:
subsequent features can add suite behavior without reopening how dependencies
are named, installed, invoked, or configured.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs role composition, public
variables, task structure, and the use of downstream role interfaces.
- [The testing house style](../../testing.md) governs repository-local
validation. Tests exercise the assembled role through native outcomes and
clean repeated convergence without reproducing the standalone suites.
- [The MVP roadmap](../mvp.md) fixes the supported platform, independently
released application roles, Git-hosted role dependencies, source-build
model, and suite/collection boundary.
- [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md)
requires the smallest direct composition and rejects supplemental state or
verification machinery without a selected requirement.
## Scope
- Turn `ansible-role-dnd-pipeline` into a conventional standalone Ansible role
with defaults, argument specifications, metadata, dependency manifests,
documentation, and focused integration coverage.
- Install the five standalone roles from their Git repositories under the
canonical names `rakestraw.audita`, `rakestraw.narratio`,
`rakestraw.notarius`, `rakestraw.seriatim`, and `rakestraw.scriptorium`.
- Pin the development dependency manifest to the reviewed commits that
completed the five standalone roles. Preserve the existing release policy
that replaces development commits with immutable role tags before a
released suite or collection is published.
- Invoke all five application roles as declared role dependencies in a fixed,
readable order.
- Select one known-compatible default application release for each component:
Audita `v0.9.1`, Narratio `v2.0.0`, Notarius `v0.6.0`, Seriatim `v1.5.0`,
and Scriptorium `v0.13.0`.
- Expose one suite-level dependency-management choice, Go Snap channel, and Go
executable, then pass those values to every application role.
- Require a suite-level WhisperX transcription URL and pass it to the Narratio
role.
- Configure Narratio with the standard binary and configuration paths managed
by the composed roles so the orchestrator can find Seriatim, Audita,
Notarius, and Scriptorium.
- Keep dependency metadata, defaults, argument specifications, README, and
focused repository-local tests aligned with the public contract.
## Non-goals
- Checking out or deploying the `campaigns` repository, including its
revision and update policy.
- Installing the `narratio-prompts` prompt library or selecting its filesystem
layout.
- Defining PromptKit profiles, Scriptorium backends, Notarius pipelines,
Narratio artifacts, publish outputs, or detailed Audita policy.
- Enabling Notarius in the Narratio pipeline before a usable Notarius pipeline
definition is supplied.
- Selecting human operators or changing their group membership.
- Defining, storing, templating, or injecting secret values or environment
files.
- Running a real recording through the end-to-end D&D workflow.
- Bundling the role into `rakestraw.dnd`; collection incorporation remains the
next repository boundary after the standalone pipeline role is functional.
- Publishing or tagging any role or collection release.
- Duplicating every public variable from every application role behind a
`dnd_pipeline_` alias.
- Reimplementing application installation, configuration templates, account
creation, or platform validation in the pipeline role.
- Supporting partial component installation, per-component enable switches,
removal, or migration from the legacy proof-of-concept role.
- Probing downstream state, inspecting task results, or validating a
successful downstream operation during production convergence.
- Testing every application-role behavior again at the suite level.
## Target End State
A consumer first installs the pipeline role's declared Git role dependencies,
then applies `rakestraw.dnd_pipeline` with a WhisperX transcription URL. The
role invokes the five standalone roles, which install their selected sources,
binaries, native configuration, and Narratio runtime state using their own
public contracts.
The pipeline role selects the five compatible application versions as one
set. A caller may replace an individual selection through the corresponding
suite variable without editing the dependency declaration or addressing the
application role directly. Shared dependency management, Go channel, and Go
executable choices likewise flow consistently to all five roles.
Narratio's managed pipeline document names the installed Seriatim, Audita,
Notarius, and Scriptorium executable paths and the managed configuration paths
for the configured applications. Notarius remains installed but is not enabled
as a Narratio stage by this foundation feature. All other optional application
settings retain their standalone-role defaults unless a caller supplies the
underlying application role variable directly.
The pipeline role does not own or reproduce downstream templates. It composes
the roles through their public variables and lets each role converge its own
state. An immediate second pipeline-role application reports no changes.
This intentionally minimal interface is a foundation, not the pipeline role's
final policy surface. Later features will give the pipeline role concrete,
opinionated D&D defaults for Audita, Narratio, Notarius, Seriatim, and
Scriptorium through the standalone roles' existing field-specific variables.
Those values will remain overrideable through ordinary inventory precedence.
The suite will add only policy it deliberately owns, rather than copying every
upstream application default.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the dependency manifest, suite public
interface, dependency declarations, cross-application path wiring,
repository documentation, and focused integration suite. This is the only
implementation repository changed by the feature.
- `ansible-role-{audita,narratio,notarius,seriatim,scriptorium}` are read-only
dependency sources and the authorities for their respective public role
interfaces. Their reviewed commits define the development dependency set.
- `../{audita,narratio,notarius,seriatim,scriptorium}` remain read-only
authorities for application behavior.
- `rakestraw-ansible` is a read-only style and historical deployment-policy
reference. Its monolithic installation and templating are not copied.
- `assets/campaigns` and `assets/narratio-prompts` are read-only authorities
for the content and layouts that later pipeline-role features will deploy.
Their availability in the workspace does not bring content deployment into
this composition-foundation feature.
- `ansible-collection-dnd` remains unchanged until collection assembly is
selected as a later feature.
- `ansible-workspace-dnd` owns this roadmap, the eventual staged plan, the
settled MVP decisions, and aggregate status.
## Constraints and Settled Decisions
- The standalone role is named `dnd_pipeline` in the `rakestraw` Galaxy
namespace. It will later be incorporated into the collection under the
shorter consumer-facing name `rakestraw.dnd.pipeline`.
- Git dependencies are installed with these canonical role names:
| Role | Repository | Development revision |
| --- | --- | --- |
| `rakestraw.audita` | `https://gitea.maximumdirect.net/eric/ansible-role-audita.git` | `d2d0b9d00b3b491ce7613ccfc8f686f3d1fa0896` |
| `rakestraw.narratio` | `https://gitea.maximumdirect.net/eric/ansible-role-narratio.git` | `7feff4728a5968b6b1dd87e83add9fa1a9066b18` |
| `rakestraw.notarius` | `https://gitea.maximumdirect.net/eric/ansible-role-notarius.git` | `cfecf37261f2595d45113235c591ee102d6f181f` |
| `rakestraw.seriatim` | `https://gitea.maximumdirect.net/eric/ansible-role-seriatim.git` | `e08c63c0b078658bdfa2d10a2e6e1e4f9372a075` |
| `rakestraw.scriptorium` | `https://gitea.maximumdirect.net/eric/ansible-role-scriptorium.git` | `8f47aa802a5e0c9dae9c0f43a1c70b3512b2c8b2` |
- Commit pins are appropriate for active development because the role
repositories do not yet publish release tags. A release must use immutable
role tags under the policy already fixed in the MVP roadmap.
- `requirements.yml` is the consumer and test bootstrap manifest for the five
Git roles. `collections/requirements.yml` declares the pinned
`community.general` dependency needed transitively by those roles.
- `meta/main.yml` declares the five application roles as dependencies and maps
the suite-owned inputs to their existing public variables. It does not use
an implementation-specific loader role.
- Dependencies execute in this order: Seriatim, Audita, Notarius,
Scriptorium, then Narratio. The order makes the downstream tools conceptually
available before the orchestrator, but the role does not add probes or
runtime validation to enforce the order's postconditions.
- Repeated Git, APT, and Snap declarations inside the five roles are accepted.
Their modules are idempotent, and consolidating them would weaken standalone
role ownership for no selected benefit.
- The suite owns only choices that must be coordinated across applications or
recorded as a compatible set. It does not alias the complete downstream
interfaces. Unmapped application-specific variables retain their ordinary
Ansible behavior and may be supplied directly by advanced callers.
- The preceding boundary governs this composition foundation only; it does not
make the finished pipeline role policy-neutral. Later D&D-configuration
features will supply opinionated values directly through the downstream
roles' public variables, preserving inventory overrides without introducing
parallel templates or complete shadow interfaces.
- The feature uses the standard application paths fixed by the MVP and current
standalone roles:
| Purpose | Path |
| --- | --- |
| Seriatim executable | `/usr/local/bin/seriatim` |
| Audita executable | `/usr/local/bin/audita` |
| Audita configuration | `/usr/local/etc/audita/config.yml` |
| Notarius executable | `/usr/local/bin/notarius` |
| Notarius configuration | `/usr/local/etc/notarius/config.yml` |
| Scriptorium executable | `/usr/local/bin/scriptorium` |
| Scriptorium configuration | `/usr/local/etc/scriptorium/config.yml` |
- Relocating those coordinated paths is not a requirement for this feature.
If a real deployment needs relocation, a later feature may introduce a
small set of coherent suite path variables rather than exposing mismatched
per-role overrides.
- Notarius is installed because it is part of the suite, but
`narratio_notarius_enabled` remains null until a later feature supplies a
complete D&D Notarius pipeline and explicitly enables it.
- Tasks requiring elevated access remain owned by the downstream roles and
use their task-level `become: true`; the pipeline role does not require
play-level escalation.
## Fixed Public Interface
| Variable | Default | Purpose |
| --- | --- | --- |
| `dnd_pipeline_audita_version` | `v0.9.1` | Audita application revision selected for the compatible set |
| `dnd_pipeline_narratio_version` | `v2.0.0` | Narratio application revision selected for the compatible set |
| `dnd_pipeline_notarius_version` | `v0.6.0` | Notarius application revision selected for the compatible set |
| `dnd_pipeline_seriatim_version` | `v1.5.0` | Seriatim application revision selected for the compatible set |
| `dnd_pipeline_scriptorium_version` | `v0.13.0` | Scriptorium application revision selected for the compatible set |
| `dnd_pipeline_manage_build_dependencies` | `true` | Whether every application role manages Git and Go |
| `dnd_pipeline_go_snap_channel` | `1.26/stable` | Go Snap channel passed to every application role |
| `dnd_pipeline_go_binary` | `/snap/bin/go` | Go executable passed to every application role |
| `dnd_pipeline_whisperx_transcribe_url` | required | External WhisperX HTTP endpoint passed to Narratio |
Argument specifications type and document each value. The WhisperX URL is
required because neither Narratio nor the suite has a valid universal
endpoint. The suite version variables select application source revisions;
they are separate from the Git revisions pinning the Ansible role
dependencies.
The role intentionally has no raw map of arbitrary downstream variables and
no parallel configuration template. Application-specific choices that are not
part of this interface continue to use the standalone roles' documented
variables.
## Simplest Viable Implementation
The implementation is primarily metadata:
1. Define the nine suite variables above in defaults and argument
specifications, omitting a default for the required WhisperX URL.
2. Declare the five named role dependencies in `meta/main.yml`, in the settled
order, and pass each dependency its selected version plus the common
dependency-management and Go values.
3. Pass the WhisperX URL and standard downstream binary/configuration paths to
the Narratio dependency.
4. Add the Git-role and collection dependency manifests used by consumers and
tests.
5. Document installation, variables, dependency bootstrap, the boundary with
application-specific variables, and an ordinary playbook example.
6. Add a focused integration driver that installs dependencies in an isolated
roles path, applies the real pipeline role, observes the assembled native
application outcome, and requires immediate clean repeated convergence.
No custom tasks are required merely to prove that role dependencies ran. The
pipeline role should not inspect downstream binaries, files, packages,
checkouts, or registered task results during production convergence. It should
not copy downstream defaults into facts or introduce an abstraction around
ordinary role dependency metadata.
## Rationale and Alternatives
Using declared role dependencies reflects the actual ownership boundary: each
application role remains responsible for its own installation and native
configuration, while the pipeline role selects and connects them. Rewriting
or including copies of downstream tasks would couple the suite to their
implementations and discard the independent-release model already selected.
A small suite-prefixed interface makes coordinated decisions explicit without
creating five complete shadow interfaces. Version selection belongs here
because the suite promises a compatible application set. Build dependency and
Go choices are common because all five roles use the same source-build model.
The WhisperX endpoint belongs here because it is required to construct the
Narratio configuration and is deployment-specific.
The standard downstream paths are suite policy rather than configurable inputs
for this first composition feature. Exposing every source, binary, and
configuration path would add aliases and cross-variable consistency rules
without a demonstrated consumer need. Advanced callers can still use
unmapped application variables where they do not conflict with coordinated
suite policy.
Keeping content, operators, secrets, and D&D processing definitions out of
this feature avoids combining several unsettled interfaces with dependency
composition. Those features can build on a running, natively valid application
suite and receive focused roadmaps of their own.
## Acceptance Criteria
### Required Role Behavior
- A documented bootstrap command installs all five standalone roles from
`requirements.yml` under their canonical names and installs the pinned
collection dependency.
- Applying the pipeline role with a valid
`dnd_pipeline_whisperx_transcribe_url` invokes all five standalone roles and
reaches their ordinary managed end state on Ubuntu 26.04 `amd64` or `arm64`.
- The default suite selections install Audita `v0.9.1`, Narratio `v2.0.0`,
Notarius `v0.6.0`, Seriatim `v1.5.0`, and Scriptorium `v0.13.0` as one
compatible development set.
- A caller can change each application revision through its corresponding
`dnd_pipeline_*_version` variable.
- The common dependency-management switch, Go channel, and Go executable are
passed to all five roles without duplicating their installation tasks.
- Narratio receives the required WhisperX URL and the standard executable and
configuration paths for all four downstream applications.
- Notarius is installed but is not enabled in the Narratio pipeline by this
feature.
- An immediate repeated role application with unchanged inputs reports no
changes.
- The role contains no copied application tasks or templates, downstream state
probes, role-private state, custom dependency loader, or production
self-validation.
- Defaults, argument specifications, dependency metadata, manifests, and
README remain aligned with the fixed interface.
- No implementation repository other than `ansible-role-dnd-pipeline` is
modified.
### Required Validation
- YAML syntax checking and production-profile ansible-lint pass for the role
and its test playbooks.
- The integration driver installs the five Git dependencies into a fresh,
isolated role path from the same manifest documented for consumers.
- One baseline application runs the real pipeline role with a test WhisperX
URL, exercises each installed application through a practical native smoke
or configuration command, validates Narratio's assembled configuration
natively, and is followed immediately by a role application reporting no
changes.
- One representative application explicitly selects Seriatim `v1.4.0`
through `dnd_pipeline_seriatim_version` and observes that selection through
Seriatim's native version interface. This proves suite forwarding without
asserting that any release remains the default or promising that arbitrary
component combinations are compatible.
- Tests do not repeat the standalone roles' missing-binary, custom-Go,
template-branch, file-metadata, package, Git, or platform matrices.
- Tests do not assert dependency task order, exact current default values,
role-variable counts, individual task results, or trusted-module
postconditions.
## Dependencies and Follow-up Work
The five application-role implementations and public interfaces are complete.
The managed host must be able to reach their application source repositories,
Ubuntu Snap infrastructure, Go module sources, and the caller-supplied
WhisperX service.
After this foundation is implemented and reviewed, later pipeline-role
features must settle and implement:
- prompt-library checkout and Scriptorium integration;
- campaign checkout, revision policy, and deployment;
- D&D-specific Audita, Notarius, Scriptorium, and Narratio policy;
- operator-selection and group-membership behavior;
- pipeline-wide secret delivery; and
- an end-to-end pipeline validation scenario.
Collection assembly remains a separate feature after the standalone pipeline
role has a stable contract. Before any released dependency manifest or
collection is published, the standalone roles must receive immutable release
tags and the development commit pins must be replaced by those tags.
The D&D-policy follow-up must inspect the asset repositories and current
application contracts, select concrete suite defaults for all five
applications, and document how callers override them. It should reuse the
standalone roles' field-specific variables rather than adding pipeline-owned
configuration templates or duplicating every downstream setting behind a new
alias.
The feature was implemented in `ansible-role-dnd-pipeline` commits `b515968`
and `61869d1`, then finalized by review remediation commit `4ea4358`. The
complete integration suite passes with fresh dependency bootstrap, native
application validation, explicit suite-level version selection, and clean
repeated convergence.
## Potential Future Hardening
- Verify signed role or application releases.
- Apply an allowlist to dependency or application repository origins.
- Add policy for hosts whose installed dependency roles differ from the
manifest used by the controller.

View File

@@ -0,0 +1,353 @@
# 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 `<prompt-library-root>/prompts` and
`<prompt-library-root>/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.

View File

@@ -0,0 +1,475 @@
# Feature 0008: Opinionated D&D Processing Configuration
Status: done
## Summary
Turn the installed application suite and deployed D&D assets into a coherent
processing configuration. The pipeline role will supply deliberately
opinionated Audita and Narratio policy, split Narratio's suite-owned processing
and artifact definitions into explicit ConfigKit fragments, and provide a
named `testing` profile for inexpensive prompt and model iteration without
changing production policy.
## Problem or Opportunity
Features 0006 and 0007 install the five applications, connect their standard
paths, and deploy valid campaigns, prompts, and schemas. The assembled role
still leaves most optional application policy unset. Narratio can validate its
minimal root document and discover content, but it does not yet describe the
D&D trimming, rendering, recap, rumor, scene-map, or per-character analysis
workflow.
A current test-machine configuration provides useful evidence of the intended
workflow, but it cannot be copied. It includes pre-Narratio-2.0 syntax,
installation-specific storage and inference settings, obsolete paths,
campaign-specific character entries, and redundant artifact dependencies.
The current application repositories remain authoritative for supported
configuration.
Narratio 2.0 also provides two useful composition mechanisms that the suite
has not yet adopted: additive root imports for independently owned base
fragments and a fixed `profiles/testing.yml` overlay. Using both will make the
production policy reviewable and make inexpensive development runs easy to
select without editing the production configuration.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the suite-owned public
interface, templates, direct desired-state tasks, and omission of
unselected application defaults.
- [The testing house style](../../testing.md) governs native behavioral
validation, explicit testing inputs, and clean repeated convergence.
- [The MVP roadmap](../mvp.md) assigns opinionated cross-application and D&D
policy to the pipeline role while keeping standalone application roles
generic.
- [Decision 0001](../../decisions/0001-minimal-module-driven-ansible.md)
requires direct module-owned convergence without supplemental state or
redundant verification.
## Scope
- Supply the complete reviewed Audita configuration as deliberate D&D suite
policy, including its context, schema, module sequence, endpoint, models,
credential environment-variable names, timeouts, retries, concurrency,
chunking, normalization, thresholds, and diagnostics settings.
- Configure Narratio's normalization, trimming, and Markdown rendering stages
through its current public contract, explicitly pinning only the schemas,
identifiers, enablement choices, and paths that form the D&D suite's
cross-stage contract.
- Use the deployed `dnd.session_bounds` prompt for transcript-bound detection.
- Define each ordinary Narratio Scriptorium artifact in its own managed YAML
fragment:
- session recap;
- hostile rumors;
- deranged rumors; and
- scene map.
- Define per-character gameplay analysis as one Narratio artifact-family
fragment over `party.characters`, not as campaign-specific artifact entries.
- Supply only the inputs declared by each current prompt definition.
- Let each production prompt select its own declared Promptkit default profile
unless the roadmap records a concrete reason for a suite override.
- Manage a valid `profiles/testing.yml` Narratio overlay that selects an
inexpensive Scriptorium profile while leaving the base production policy
and inherited Audita configuration unchanged.
- Expose the suite-owned testing-profile choice through normal Ansible
inventory precedence.
- Compose the base fragments through an explicit ordered
`narratio_configkit_imports` list in the standalone Narratio role's root
configuration.
- Create and manage the required `conf.d`, `artifacts`,
`artifact-families`, and `profiles` directories and their suite-owned files
under `/usr/local/etc/narratio`.
- Document production and testing invocations, the imported layout, public
variables, and the boundary with later pipeline features.
- Extend focused integration coverage for both base and `testing` resolution,
representative artifact relationships, party-driven family expansion, and
immediate clean repeated convergence.
## Non-goals
- Enabling Narratio's Notarius stage or installing the uploaded Notarius
pipeline. Its multi-stage D&D extraction, campaign reference bindings,
output descriptors, and runtime directories remain a separate feature.
- Configuring S3 or other remote storage, publishing outputs, upload behavior,
or cleanup-after-publish.
- Selecting a default campaign. Campaign choice remains an inventory or
invocation decision.
- Delivering API keys, object-storage credentials, environment files, or a
general secret-management mechanism.
- Selecting human operators or managing their Narratio group membership.
- Adding a scheduler, service, or automated invocation.
- Running WhisperX, Audita model calls, Scriptorium model calls, Notarius, or
a complete transcript during integration tests.
- Copying the test-machine configuration verbatim or preserving its obsolete
Narratio, campaign, Scriptorium, or credential paths.
- Duplicating prompt content, prompt schemas, built-in Promptkit profiles, or
application validation rules in the pipeline role.
- Modifying the standalone application roles or upstream application source.
- Collection assembly, role releases, asset release policy, upgrade/removal
behavior, or end-to-end production validation.
## Target End State
The standalone Narratio role continues to own
`/usr/local/etc/narratio/pipeline.yml`. That root document contains the
installation paths already supplied by the pipeline role and an explicit list
of suite-owned relative imports. The pipeline role owns the imported files:
```text
/usr/local/etc/narratio/
├── pipeline.yml
├── conf.d/
│ └── processing.yml
├── artifacts/
│ ├── session-recap.yml
│ ├── hostile-rumors.yml
│ ├── deranged-rumors.yml
│ └── scene-map.yml
├── artifact-families/
│ └── character-meta-analysis.yml
└── profiles/
└── testing.yml
```
Each base artifact or family key is declared by exactly one fragment. The
root uses explicit `path` imports rather than globs; Narratio therefore loads
only the files selected by current suite policy, even if an obsolete file is
left on a previously managed host. Imported maps remain additive and no two
base sources claim the same leaf.
The production configuration uses the deployed prompt definitions and their
frontier-oriented default profiles. Audita uses the selected
`https://inference.ai.rakestrawhome.com/v1` endpoint and
`google/gemma-4-31b-it` proposal and validation model. Narratio's canonical
processing paths and schemas are suite-owned contracts rather than incidental
copies of application defaults. Session recap consumes the final trimmed
transcript and may consume the previous session's recap. Hostile and deranged
rumors consume the current recap, allowing Narratio to infer their dependency
without a duplicate `depends_on` declaration. Scene map is configured as an
available, normally disabled artifact. Character analysis is an available
party-driven family whose generated members receive `character.name` and
`character.class_summary` through family member variables.
The installed `testing` profile is a valid overlay selected with
`--profile testing`. It selects `gemini-flash-latest` for each Scriptorium
artifact and artifact family while inheriting the base topology, paths,
prompts, inputs, outputs, and enabled state. Audita inherits the same endpoint
and model in both modes for now, so the overlay does not restate its base
configuration. The testing profile neither imports files nor contains
credentials. Operators can validate, inspect, or run the same session under
base or testing policy without modifying an Ansible-managed file.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the suite variables, Narratio fragment and
testing-profile templates, direct directory/file convergence, dependency
variable wiring, consumer documentation, and integration coverage. It is
the only implementation repository expected to change.
- `ansible-role-narratio` remains unchanged. It owns the root pipeline
template and the public `narratio_configkit_imports` and stage variables
through which the suite composes it.
- `ansible-role-audita` remains unchanged. It owns Audita's field-specific
configuration interface; the pipeline role selects only intentional D&D
policy through that interface.
- `ansible-role-scriptorium`, `assets/narratio-prompts`, and `../promptkit`
remain unchanged authorities for source-directory configuration, prompt
contracts, and built-in production/testing profile choices.
- `../audita` and `../narratio` remain unchanged authorities for current
application configuration and native inspection behavior.
- `ansible-role-notarius` and `../notarius` are read-only inputs for the later
D&D extraction feature.
- `rakestraw-ansible` and the uploaded test-machine configurations are
historical and operational references, not application contracts.
- `ansible-workspace-dnd` owns this roadmap, the later implementation plan,
settled MVP decisions, and aggregate status.
## Constraints and Settled Decisions
- Standalone application roles remain generic. Every concrete value added by
this feature must represent policy deliberately owned by the D&D suite.
- Application defaults observed in documentation or the uploaded files are
not copied merely to restate them. An explicit suite value must preserve a
chosen outcome across upstream default changes.
- The pipeline explicitly owns a value when another stage, artifact, prompt,
or future publishing rule relies on its schema, identifier, enabled state,
or path. Behavior confined to Narratio inherits Narratio's application
default unless the suite has independently selected that behavior as policy.
- The pipeline role does not duplicate Narratio's root template. It acts as a
caller: the standalone role renders the root and the pipeline role deploys
the suite-owned fragments named by that root.
- Every ordinary artifact and every artifact family has its own source and
installed file. General stage policy may share `conf.d/processing.yml`.
- Imports are explicit relative `path` entries. Globs are not used because
the role does not need directory discovery and must not activate stale
files accidentally.
- The imported files cannot contain `configkit`, nested imports, or profile
directives. The `testing` overlay cannot import or stack other profiles.
- Suite-managed configuration directories are `root:narratio` mode `0750`;
files are `root:narratio` mode `0640`, matching the established Narratio
configuration boundary.
- The role declares directory and template state directly. It does not
inspect files first, validate production configuration during convergence,
keep manifests, or track fragment digests.
- The base artifact definitions omit `profile_id` when the deployed prompt's
declared default is the selected production policy.
- Artifact inputs must match the current prompt contracts:
- session recap: required `transcript`, optional `recap`;
- hostile and deranged rumors: required `recap`;
- scene map: required `transcript`; and
- character analysis family: required `transcript`, optional `recap`, plus
member variables for `character_name` and `character_class`.
- A `narratio.artifact.session_recap` input already creates the rumor
dependency. The base fragments do not repeat that edge with `depends_on`.
- Scene map and character analysis are configured but disabled by default;
Narratio's explicit artifact selection may still run their concrete entries.
- The character family uses `for_each: party.characters`, an output path with
exactly one `{character_id}` token, and member selectors
`character.name` and `character.class_summary`. It contains no hard-coded
campaign character names.
- Production and testing policy never embeds secret values. Credential
delivery remains a later feature.
- The testing profile is a single valid overlay at the native fixed location.
It overrides each Scriptorium artifact and family `profile_id` with the
suite's `gemini-flash-latest` testing-profile variable rather than
duplicating complete definitions. Audita deliberately uses the same base
endpoint and models under both configurations.
- Each fixed artifact or family fragment has one complete native-mapping
variable: `dnd_pipeline_narratio_session_recap_artifact`,
`dnd_pipeline_narratio_hostile_rumors_artifact`,
`dnd_pipeline_narratio_deranged_rumors_artifact`,
`dnd_pipeline_narratio_scene_map_artifact`, and
`dnd_pipeline_narratio_character_analysis_family`. The file names, imports,
and top-level source keys remain fixed suite topology; callers customize the
mapping and disable an available source with `enabled: false` rather than
removing its managed fragment or import.
## Selected Narratio Coordination Policy
The pipeline role pins the following effective Narratio fields because they
connect processing stages, prompt contracts, or stable suite outputs. A value
that currently equals an application default is still intentional suite policy
when an upstream change would otherwise break that connection.
| Native Narratio field | D&D suite default | Coordination purpose |
| --- | --- | --- |
| `pipeline.seriatim.output_schema` | `seriatim-intermediate` | Establishes the merge-stage transcript contract. |
| `pipeline.audita.output_schema` | `audita-v1` | Matches the Audita configuration and adapter output contract. |
| `pipeline.normalize.output_path` | `transcripts/final.json` | Provides the canonical normalized transcript source. |
| `pipeline.normalize.output_schema` | `seriatim-intermediate` | Provides the canonical schema consumed by later stages. |
| `pipeline.trim.enabled` | `true` | Makes the trimmed transcript part of the selected D&D workflow. |
| `pipeline.trim.output_path` | `transcripts/final.trimmed.json` | Provides the canonical transcript consumed by D&D artifacts. |
| `pipeline.trim.bounds.prompt_id` | `dnd.session_bounds` | Selects the deployed D&D bounds prompt. |
| `pipeline.trim.bounds.transcript_input_name` | `transcript` | Matches that prompt's declared input contract. |
| `pipeline.trim.bounds.output_path` | `artifacts/session_bounds.json` | Provides a stable bounds artifact location. |
| `pipeline.render.enabled` | `true` | Selects rendered transcripts as a suite outcome. |
| `pipeline.render.format` | `markdown` | Selects the suite's rendered transcript format. |
The fixed artifact mappings own these output paths:
| Source | D&D suite output |
| --- | --- |
| `session_recap` | `artifacts/session_recap.md` |
| `hostile_rumors` | `artifacts/hostile_rumors.md` |
| `deranged_rumors` | `artifacts/deranged_rumors.md` |
| `scene_map` | `artifacts/scene_map.json` |
| `character_meta_analysis` family | `artifacts/character_meta_analysis/{character_id}.md` |
The processing fragment omits Narratio-local choices such as reports,
timeouts, debug rendering, work-directory retention, render title, timestamp,
segment-ID, and metadata presentation, and the bounds prompt profile. Narratio
continues to supply those defaults. Likewise, the Narratio Audita adapter does
not repeat Audita's endpoint, models, module sequence, tuning, or diagnostic
settings: it uses the pipeline-managed Audita configuration file. The Audita
output schema is the deliberate exception because it spans that application
boundary, and one suite value must feed both configurations.
Audita does not choose a fixed final transcript path in this integration.
Narratio supplies the run-specific `--output` path when invoking Audita and
then normalizes the result to the canonical path above. The role therefore
does not invent a separate Audita output-path setting.
## Selected Audita and Testing Policy
The pipeline role deliberately owns all of the following Audita values. They
are suite defaults, not assertions about Audita's upstream defaults, and each
remains replaceable through the corresponding suite-prefixed role variable.
| Native Audita field | D&D suite default |
| --- | --- |
| `pipeline.modules` | `[glossary, homophones, glossary, spoken_word, grammar]` |
| `output.schema` | `audita-v1` |
| `llm.proposal.base_url` | `https://inference.ai.rakestrawhome.com/v1` |
| `llm.proposal.model` | `google/gemma-4-31b-it` |
| `llm.proposal.api_key_env` | `AUDITA_LLM_API_KEY` |
| `llm.proposal.timeout` | `900s` |
| `llm.proposal.max_retries` | `3` |
| `llm.validation.base_url` | `https://inference.ai.rakestrawhome.com/v1` |
| `llm.validation.model` | `google/gemma-4-31b-it` |
| `llm.validation.api_key_env` | `AUDITA_VALIDATION_LLM_API_KEY` |
| `llm.validation.timeout` | `900s` |
| `llm.validation.max_retries` | `3` |
| `concurrency.total_llm` | `4` |
| `concurrency.proposal_llm` | `4` |
| `concurrency.validation_llm` | `4` |
| `chunking.target_sections` | `8` |
| `chunking.max_section_tokens` | `6144` |
| `chunking.min_section_tokens` | `2048` |
| `normalization.max_segment_gap` | `3s` |
| `normalization.ellipsis_gap` | `3s` |
| `normalization.max_segment_duration` | `240s` |
| `normalization.max_segment_tokens` | `2048` |
| `thresholds.glossary` | `0.8` |
| `thresholds.homophones` | `0.8` |
| `thresholds.spoken_word` | `0.8` |
| `thresholds.grammar` | `0.8` |
| `context.description` | `The following transcript was recorded during a Dungeons & Dragons game session. It may contain some unrelated pre-session or post-session banter, in addition to actual D&D gameplay.` |
| `diagnostics.work_dir` | `/tmp/audita` |
| `diagnostics.retention` | `auto` |
The repeated `glossary` entry is intentional and preserves the selected
multi-pass module sequence. Environment-variable names are configuration, not
secret values; the later secret-delivery feature will provide their contents.
The testing overlay uses one suite variable whose default is
`gemini-flash-latest` for every Scriptorium artifact and artifact family.
Callers may replace that profile normally. Audita uses the production endpoint
and models in testing until the suite deliberately selects alternatives; the
overlay omits identical Audita fields rather than writing them twice. These
model choices are expected to evolve rapidly and can be updated as ordinary
suite policy without changing the fragment architecture.
## Simplest Viable Implementation
The production change should remain a small configuration extension:
1. Add only the suite variables required by the selected Audita policy,
selected Narratio coordination policy, fragment mappings, and
testing-profile override; align the argument specification.
2. Pass the Audita choices and explicit Narratio import list through the
existing dependency interfaces.
3. Create the four Narratio configuration subdirectories with one
`ansible.builtin.file` loop.
4. Render the processing fragment, four artifact fragments, one family
fragment, and testing overlay with one `ansible.builtin.template` loop.
5. Update the README and extend the existing integration driver with native
base/testing validation and a clean repeat.
No preliminary `stat`, configuration assembly fact, handler, validation
command, checksum, manifest, or fragment cleanup task is required. Explicit
imports make an obsolete unreferenced file inert without destructive directory
reconciliation.
## Rationale and Alternatives
ConfigKit fragments preserve the application's native composition model and
give each artifact a focused review boundary. Rendering one monolithic
Narratio mapping through the standalone root variable would produce a valid
file but would discard that operational and editorial advantage. Reimplementing
the entire root template in the pipeline role would duplicate the standalone
role and create competing configuration ownership.
Explicit imports are preferred to globs because the suite already knows every
managed fragment. A glob would add discovery behavior and could keep a removed
artifact active through a stale file. Deleting and recreating the directory on
every run would harm idempotence and caller safety merely to compensate for
that avoidable ambiguity.
One testing overlay is preferable to a second complete configuration tree.
Profiles replace only selected leaves after base composition, so topology and
paths cannot drift between production and development. The selected
`gemini-flash-latest` default provides immediate value while remaining one
ordinary role-default change when model economics evolve.
The uploaded Notarius pipeline is concrete and valid, but adding it here would
combine a ten-lane extraction contract, campaign-reference mapping, output
descriptor mapping, runtime directories, and model policy with an already
coherent Narratio/Scriptorium feature. Keeping it separate makes both reviews
smaller and preserves a clear acceptance boundary.
## Acceptance Criteria
### Required Configuration Behavior
- The pipeline role produces the documented imported configuration layout
with one file per artifact and artifact family.
- The root pipeline document contains the exact explicit relative imports and
no glob imports.
- Base Narratio configuration validates natively for either deployed campaign.
- The effective base configuration uses the selected Seriatim, Audita,
normalization, trimming, bounds, and rendering contracts and the canonical
artifact output paths documented above.
- `narratio config artifacts` reports a valid recap-to-rumor graph and expands
the character-analysis family for the selected campaign.
- The recap, rumor, scene-map, and character-family definitions use only inputs
and variables supported by their deployed prompt definitions and Narratio's
current source vocabulary.
- The two rumor dependencies are inferred from their recap input sources and
are not duplicated as explicit ordering edges.
- Scene map and the character-analysis family are available but disabled by
default; recap and both rumor artifacts are enabled.
- Production artifacts inherit their selected profiles from the prompt
definitions unless an expressly agreed suite override is documented.
- Audita's managed configuration contains the selected D&D policy and remains
valid through Audita's native validator.
- The same suite-owned `audita-v1` schema is supplied to Audita's managed
configuration and Narratio's Audita adapter; Narratio supplies Audita's
run-specific output path rather than relying on a second fixed path.
- `profiles/testing.yml` is a valid, independently selectable Narratio profile
that selects the configured inexpensive Scriptorium profile for every
artifact and family and inherits base workflow structure.
- The testing profile does not repeat Audita configuration while production
and testing deliberately share the same Audita endpoint and models.
- Base and testing configuration can be compared with
`narratio config diff default testing` without requiring a model call.
- All suite-managed configuration remains readable by the `narratio` group and
is not made writable by runtime or human operator accounts.
- An immediate repeated role application with unchanged inputs reports no
changes.
- The role contains no configuration probes, production self-validation,
fragment manifests, duplicate root template, secrets, Notarius integration,
storage, or publishing behavior.
### Required Validation
- YAML syntax checking and production-profile ansible-lint pass for the role
and test playbooks.
- The complete existing pipeline integration entry point continues to install
the pinned role combination and validate asset discovery.
- Audita natively validates the role-managed D&D configuration.
- Narratio natively validates both base and `testing` configuration with an
explicitly selected deployed campaign.
- Narratio's native artifact inspection demonstrates one enabled ordinary
artifact, one inferred dependency, and representative family expansion.
- A test explicitly supplies a representative testing Scriptorium profile and
observes its effective selection; it does not assert that the same value
remains the role's current default.
- Scriptorium can resolve the representative production and testing profiles
through its native inspection interface without making a provider request.
- The immediate repeat reports `changed=0` and `failed=0`.
- Tests do not snapshot full rendered files, enumerate every character or
artifact, inspect template/file task results, test filesystem metadata, or
reproduce ConfigKit, Narratio, Audita, Scriptorium, or Promptkit validation.
## Dependencies and Follow-up Work
Features 0001 through 0007 and the standalone-role test-suite simplification
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 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 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
- Use ConfigKit source inspection in operational diagnostics to show which
managed fragment supplied an effective value.
- Add a controlled cleanup policy for obsolete suite fragments if accumulated
inert files become an operational problem.

View File

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

View File

@@ -0,0 +1,544 @@
# Feature 0010: D&D Notarius Extraction Integration
Status: done
## 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 boundary provide the maintained replacement. Narratio 2.0 names
Notarius v0.6.0 as its subprocess baseline, while Notarius v0.7.0 expressly
preserves that subprocess receipt and extraction-artifact contract. The
Notarius upgrade therefore changes deployment configuration without requiring
a Narratio adapter change. 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.
- Advance the pipeline role's selected Notarius application version to v0.7.0
and pin its Notarius role dependency to the reviewed revision that provides
the version 5 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`, and configure Notarius to create its
chunk-plan and checkpoint stores beneath that root.
- Apply Feature 0009's established access and default ACL policy to the new
cache root so content created by either supported invocation identity remains
group-writable and world-readable.
- Keep Notarius enabled under the existing `testing` overlay. Testing and
production select the same Notarius pipeline and workload profile until the
suite chooses a distinct testing profile strategy.
- Document the reference boundary, lane-to-source mapping, runtime-state
policy, production/testing behavior, and supported caller customization.
- Extend focused integration coverage for native Notarius validation,
Narratio base/testing resolution, representative reference and output
wiring, and immediate clean repeated convergence.
## Non-goals
- Changing any application's native configuration fields or duplicating a
standalone role's root configuration template in the pipeline role.
- Making the standalone Notarius role manage imported fragments; fragment
deployment remains the responsibility of the caller that selects an
import.
- Copying the uploaded test-machine configuration verbatim.
- Installing a filesystem PromptKit profile for Notarius. Notarius v0.7.0
already embeds the selected production `dnd-extraction` fallback profile.
- Defining a second Notarius pipeline solely to select an inexpensive testing
model, or otherwise adding profile inheritance that Notarius does not
natively provide.
- Binding a spell catalog before the campaign registry declares one.
- Publishing, rendering, or otherwise consuming the new extraction sources in
Scriptorium artifacts.
- Selecting a default campaign.
- Delivering API keys, provider credentials, environment files, or a general
secret-management mechanism.
- Running Notarius extraction, making model calls, or processing a complete
transcript during integration tests.
- Managing output retention, cache cleanup, or debug retention.
- Adding checkpoint-resume control to Narratio or changing Narratio's
subprocess invocation to pass `--resume` or `--config-profile`.
- Installing a systemd service, timer, scheduler, or other unattended
invocation mechanism.
- Selecting human operator accounts or changing their membership in the
`narratio` group.
- Revising the general configuration ownership, dependency ordering, ACL
dependency, or existing shared roots established by Feature 0009.
- Delivering or populating the future restricted `secrets/` directory.
- Modifying upstream application source, embedded Notarius prompts, schemas,
modules, codecs, or validators.
- Collection assembly, role releases, storage/publishing, upgrade/removal
behavior, or end-to-end production validation.
## Target End State
The standalone Notarius role continues to own the version 5 root document at
`/usr/local/etc/notarius/config.yml`. Its public interface exposes the native
`configkit.imports` list, and the pipeline role selects the explicit relative
import `pipelines/dnd-session.yml`. The pipeline role owns that fragment and
renders the complete `dnd_pipeline_notarius_pipelines` map into it, producing
one native `dnd-session` definition by default. The definition follows the
Notarius v0.7.0 maintained complete D&D topology:
```text
Seriatim transcript
-> dnd/scenes chunking
-> describe-session
item-registry
npc-registry
location-registry
scene-descriptions
-> extract-events
item-occurrences
spells
combat-turns
npc-occurrences
location-occurrences
-> track-enemies
enemy-events
-> JSON bundle, chunk map, and evidence context
```
Feature 0009 already makes application configuration service-owned and
world-readable. The Notarius root document and new suite fragment retain that
`narratio:narratio`, `0755` directory, and `0644` file policy through the
standalone role's established ownership and mode interface.
The `extract-events` step consumes the four generated outputs from
`describe-session` under their declared internal reference slots. The
`track-enemies` step consumes the generated NPC registry and scene
descriptions from `describe-session` and the generated combat turns and NPC
occurrences from `extract-events`. Those handoffs are part of the Notarius
pipeline and never appear in Narratio's CLI reference map.
Narratio's effective base configuration enables Notarius, selects the managed
configuration and `dnd-session`, and supplies three campaign-owned references:
| Notarius selector | Prepared Narratio source |
| --- | --- |
| `party` | `narratio.input.party` |
| `players` | `narratio.input.players` |
| `glossary` | `narratio.input.glossary` |
Narratio snapshots those inputs for each invocation and passes their absolute
paths with `--reference`. No campaign path appears in Notarius configuration.
The optional `spell_catalog` binding is absent because neither deployed
campaign currently declares `inputs.spell_catalog_file`. A caller that adds
that campaign input can extend the suite reference map with
`spell_catalog: narratio.input.spell_catalog` without changing either
application role.
Narratio accepts all ten configured lanes using these exact v1 contracts and
registers each accepted payload as `narratio.extraction.<output-key>`:
| Narratio output key | Lane ID | Schema ID | Module key |
| --- | --- | --- | --- |
| `item_registry` | `item-registry` | `notarius.dnd.item_registry` | `dnd/item-registry` |
| `npc_registry` | `npc-registry` | `notarius.dnd.npc_registry` | `dnd/npc-registry` |
| `location_registry` | `location-registry` | `notarius.dnd.location_registry` | `dnd/location-registry` |
| `scene_descriptions` | `scene-descriptions` | `notarius.dnd.scene_descriptions` | `dnd/scene-descriptions` |
| `item_occurrences` | `item-occurrences` | `notarius.dnd.item_occurrences` | `dnd/item-occurrences` |
| `spells` | `spells` | `notarius.dnd.spells` | `dnd/spells` |
| `combat_turns` | `combat-turns` | `notarius.dnd.combat_turns` | `dnd/combat-turns` |
| `npc_occurrences` | `npc-occurrences` | `notarius.dnd.npc_occurrences` | `dnd/npc-occurrences` |
| `location_occurrences` | `location-occurrences` | `notarius.dnd.location_occurrences` | `dnd/location-occurrences` |
| `enemy_events` | `enemy-events` | `notarius.dnd.enemy_events` | `dnd/enemy-events` |
Every entry requires `media_type: application/json` and
`schema_version: v1`. Narratio validates the received descriptor before
registering the source; it does not infer contracts from filenames.
Narratio supplies its run-specific staging root through Notarius's
`--output-dir` override, so the suite does not set Notarius's global
`output.directory`. Reconstructible Notarius state uses the FHS cache layout:
```text
/var/cache/notarius/
├── chunk-plans/
└── checkpoints/
```
The pipeline role creates the root as `narratio:narratio` mode `2775`, sets
chunk-plan mode to `auto`, enables checkpoint recording, and configures both
child paths. Notarius creates cache entries with conventional maximum creation
modes and leaves their effective modes to deployment provisioning, process
umask, setgid inheritance, and default ACLs. The suite applies a default ACL
that retains owner and group write access and world read/traverse access for
new cache content. Narratio and its Notarius subprocess may run as the
dedicated `narratio` account or as a human member of the `narratio` group.
Chunk plans are reused automatically; checkpoints are recorded but are not
reused because Narratio does not pass `--resume`. The debug root remains
unset. The selected Notarius process working directory is
`/usr/local/etc/notarius`, matching the managed configuration location; no
relative profile or reference paths depend on it.
The cache root receives the same setgid and default-ACL policy that Feature
0009 applies to Narratio's existing shared roots. Non-secret content created
beneath it remains writable by the shared group and readable by other local
users. The suite does not create or populate a `secrets/` directory.
The base Narratio configuration and the `testing` ConfigKit overlay both run
the extraction stage using Notarius's embedded `dnd-extraction` profile. The
testing overlay continues to override only the Scriptorium profile selections;
it does not disable or restate Notarius. A later feature may select a distinct
inexpensive Notarius testing profile without changing the pipeline topology.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the D&D pipeline map and imported fragment,
Narratio integration mappings, Notarius dependency-variable wiring, the new
cache root and its inherited shared-access policy, testing-overlay choice,
consumer documentation, and suite integration coverage.
- `ansible-role-notarius` owns the generic Notarius v0.7.0 installation,
version 5 root configuration, optional ConfigKit import interface, focused
role documentation, and role-local integration coverage. It does not own or
render the suite's imported D&D fragment.
- `ansible-role-audita`, `ansible-role-narratio`, and
`ansible-role-scriptorium` remain unchanged. The Narratio role owns its generic
Notarius adapter fields and ConfigKit-aware root configuration.
- `../notarius` is the read-only authority for configuration version 5, the
maintained D&D pipeline, embedded profile, module handoffs, and lane
contracts.
- `../narratio` is the read-only authority for prepared campaign sources,
subprocess invocation, output acceptance, and profile overlay behavior.
- `assets/configs/notarius/config.yml` is an operational reference only. Its
useful topology is adapted, while its campaign paths and runtime roots are
not copied.
- `assets/campaigns` remains unchanged and continues to own the campaign
registry inputs that Narratio prepares.
- `ansible-workspace-dnd` owns this roadmap, the later implementation plan,
settled MVP decisions, and aggregate status.
## Constraints and Settled Decisions
- This feature advances the standalone role default and pipeline application
selection from Notarius v0.6.0 to v0.7.0. Narratio remains at v2.0.0.
- Narratio v2.0.0 documents Notarius v0.6.0 as its invocation baseline, but
Notarius v0.7.0 preserves the subprocess receipt and extraction-artifact
contracts. Version 5 configuration migration is confined to the Notarius
role and the suite-owned Notarius fragment.
- The pipeline dependency manifest must pin the reviewed standalone Notarius
role revision that implements this v0.7.0/configuration-version-5 contract.
- 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. Advance the pipeline's Notarius application selection and standalone-role
dependency pin, then 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 pipeline role selects Notarius v0.7.0 and its dependency manifest pins
the reviewed standalone-role revision that supplies the version 5 interface.
- 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 0009 and the standalone-role test-suite simplification
are complete, so the shared filesystem and execution prerequisite is
satisfied. Implementation depends on the current Notarius v0.7.0 maintained
D&D configuration and ConfigKit contract, the compatible Narratio v2.0.0
subprocess boundary, campaign sources deployed by Feature 0007, and trimmed
transcript policy defined by Feature 0008.
The next suite feature should select which extraction sources feed new or
existing Scriptorium artifacts, or address pipeline-wide credential delivery
if real end-to-end execution requires it first. Later work should cover
storage and publishing, optional operator selection and membership management,
collection assembly, release pinning, and an end-to-end workflow using actual
external services. A separate feature may add inexpensive Notarius testing
extraction if a concrete workflow justifies a second operator profile or
application configuration.
## Potential Future Hardening
- Add explicit cache and debug retention policy once operational use provides
concrete retention requirements.
- Define credential delivery beneath the restricted `secrets/` subtree. No
further Notarius cache-permission feature is required for shared invocation.
- Pin content repositories to immutable releases when their upstream projects
begin publishing them.

View File

@@ -0,0 +1,389 @@
# Feature 0011: Managed Pipeline Credentials and Notarius Reuse
Status: done
## Summary
Upgrade the generic Narratio role and D&D pipeline to Narratio v2.1.0, manage
provider credentials through Narratio's conventional ConfigKit secrets
directory, and use the release's typed Notarius credential and checkpoint-reuse
controls. Credential values remain outside ordinary application YAML and are
readable only by the selected runtime user and group. Ordinary pipeline runs
reuse compatible Notarius checkpoints, while forced extraction retains
Narratio's native refresh behavior.
## Problem or Opportunity
The pipeline role currently writes credential reference names but manages no
credential values. A caller must prepare the invoking environment through an
external mechanism before a real run can reach the selected model providers.
The installed Narratio v2.0.0 release also cannot forward a selected provider
credential to Notarius. Its Notarius child receives a restricted environment,
and the v2.0 configuration contract exposes no typed credential field. The
pipeline records Notarius checkpoints but cannot ask Notarius to reuse them.
Narratio v2.1.0, immutable tag `v2.1.0` at `c45e042`, resolves both application
contract gaps. It adds optional `notarius.llm_api_key`, `notarius.resume`, and
`notarius.chunk_cache` fields without requiring migration of existing v2
configuration. The credential field resolves through the existing process
environment or secrets-directory bootstrap, forwards only the exact selected
name and value, and participates in the application's existing redaction
boundary. Ordinary extraction may request checkpoint reuse; forced extraction
omits resume and refreshes the active chunk plan.
The suite separately configures Audita proposal and validation with different
environment names even though both use the same endpoint and model. Narratio's
Audita boundary accepts one typed credential. This feature therefore
coordinates both suite-default Audita sections on `AUDITA_LLM_API_KEY` while
retaining their existing independently overrideable variables.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs the direct desired-state
implementation, native configuration interface, and ordinary module
convergence.
- [The testing house style](../../testing.md) governs synthetic, native,
behavior-oriented validation without live provider calls or filesystem
metadata assertions.
- [The MVP roadmap](../mvp.md) assigns pipeline-wide secret delivery,
application-version coordination, and cache policy to the suite role.
- [Decision 0002](../../decisions/0002-shared-readable-pipeline-filesystem-policy.md)
defines the selected runtime group as the authorization boundary and fixes
`0750` directory and `0640` file modes for shared credential material.
- [Feature 0009](0009-shared-pipeline-filesystem-and-execution.md) establishes
the service-user and existing-group-member invocation model.
- [Feature 0010](0010-dnd-notarius-extraction-integration.md) establishes the
Notarius pipeline, FHS cache roots, automatic chunk-plan reuse, and checkpoint
recording extended by this feature.
- Narratio's immutable v2.1.0 release documentation and current configuration
and Notarius integration references are authoritative for the application
fields, resolution semantics, forced-run behavior, and redaction contract.
## Scope
- Advance the standalone Narratio role's selected application release from
v2.0.0 to v2.1.0 without changing its established source-build task flow.
- Expose the three new native optional fields through nullable, field-specific
role variables: `narratio_notarius_llm_api_key`,
`narratio_notarius_resume`, and `narratio_notarius_chunk_cache`.
- Keep the standalone role generic. All three variables default to null and
are omitted unless a caller selects them, leaving Narratio's native defaults
in control.
- Advance the pipeline role's compatible Narratio application version to
v2.1.0 and pin its Narratio role dependency to the reviewed revision that
provides the new interface.
- Use `/usr/local/etc/narratio/secrets`, the conventional directory adjacent
to `/usr/local/etc/narratio/pipeline.yml`, as the suite's sole managed
credential location.
- Create that directory as the selected pipeline runtime user and group with
mode `0750`.
- Add one public `dnd_pipeline_secrets` mapping from environment-variable names
to string file contents. Each supplied entry means that the named credential
file must be present with that content; an omitted key is unmanaged.
- Default `dnd_pipeline_secrets` to an empty mapping so the role never invents
credentials and remains usable with externally prepared process environment
values.
- Validate selected keys as environment-variable names and values as strings
before constructing a destination path.
- Write supplied credential files as the selected runtime user and group with
mode `0640`.
- Suppress credential values from Ansible task output during validation,
creation, and updates.
- Keep ordinary application configuration limited to non-secret credential
reference names.
- Coordinate Audita proposal and validation on the suite-default
`AUDITA_LLM_API_KEY` name and pass that name through the standalone Narratio
role's existing `narratio_audita_llm_api_key` interface.
- Add `dnd_pipeline_narratio_notarius_llm_api_key`, default it to
`OPENROUTER_API_KEY` for Notarius's selected production profile, and pass it
through Narratio's typed Notarius credential field.
- Add `dnd_pipeline_narratio_notarius_resume`, default it to true, and pass it
through Narratio so ordinary extraction requests reuse of the checkpoints
already recorded by the suite's Notarius configuration.
- Expose Narratio's native `notarius.chunk_cache` in the standalone role but do
not duplicate it behind a suite variable or set it from the pipeline role.
The suite already configures Notarius's ordinary chunk-plan mode as `auto`;
Narratio v2.1.0 independently owns its forced-extraction refresh override.
- Preserve Scriptorium's application-owned `api_key_env` profile selection.
Narratio's secrets bootstrap supplies the selected environment value and the
existing Scriptorium adapter passes that named credential to its child.
- Document the mapping interface, Ansible Vault inventory pattern, process
environment precedence, shared-group authorization boundary, application
credential flow, and checkpoint-reuse policy.
- Add focused integration coverage using distinctive synthetic values and
native Narratio configuration loading. No default test contacts a model
provider.
## Non-goals
- Storing raw credentials in Narratio, Audita, Notarius, or Scriptorium YAML.
- Providing real credentials, unencrypted example values, or a default secret
mapping.
- Implementing Ansible Vault, choosing a vault password mechanism, or requiring
one specific inventory encryption workflow.
- Integrating an external secret manager, cloud vault, hardware-backed key
store, or dynamic credential broker.
- Making the pipeline role authoritative for files omitted from
`dnd_pipeline_secrets`, purging the whole directory, or recursively changing
pre-existing content.
- Adding a launcher script, shell profile, environment file, systemd unit,
scheduler, or persistent service merely to inject credentials.
- Passing arbitrary caller-defined environment variables through Narratio's
subprocess boundary.
- Managing human accounts or their membership in the runtime group.
- Running Audita, Notarius, or Scriptorium against a live endpoint during the
default integration suites.
- Testing Notarius checkpoint reuse end to end in the Ansible role. Narratio
and Notarius own that behavior; the role validates the selected native
configuration and immediate Ansible convergence.
- Setting Narratio's optional `notarius.chunk_cache` field redundantly when
the deployed Notarius configuration already selects `auto`.
- Changing Narratio's native forced-extraction refresh policy.
- Rotating credentials, retaining prior values, validating provider
authorization, or recovering deliberately corrupted secret files.
- Adding storage or publishing credentials before the suite selects a storage
or publishing feature.
- Modifying any upstream application source.
## Target End State
The standalone Narratio role installs v2.1.0 by default and can render all
three new Notarius fields when a caller supplies them. It owns no credential
files and selects no D&D-specific credential or cache policy.
The pipeline role owns this conventional restricted subtree:
```text
/usr/local/etc/narratio/
├── pipeline.yml
└── secrets/ narratio:narratio 0750
├── AUDITA_LLM_API_KEY narratio:narratio 0640
└── OPENROUTER_API_KEY narratio:narratio 0640
```
The filenames are suite-selected reference names, never credential values.
The selected runtime user and group remain configurable through the existing
pipeline interface.
A consumer may keep encrypted values in inventory without embedding any value
in ordinary configuration:
```yaml
dnd_pipeline_secrets:
AUDITA_LLM_API_KEY: "{{ vault_dnd_audita_llm_api_key }}"
OPENROUTER_API_KEY: "{{ vault_dnd_openrouter_api_key }}"
```
The role owns only the supplied named entries for this invocation and leaves
every omitted name alone. The actual `vault_dnd_*` values belong in encrypted
inventory and must not appear in examples, plans, test logs, commits, or
ordinary generated configuration.
When Narratio runs without `--secrets-dir`, it discovers the sibling directory
and loads its immediate regular files before resolving the pipeline. An
already-set process environment value wins over the corresponding file. The
base and `testing` profiles use the same delivery mechanism; profiles select
models and application profiles, not a second credential store.
The suite deliberately uses `narratio:narratio`, directory mode `0750`, and
file mode `0640` rather than Narratio's general single-user recommendation of
`0700` and `0600`. Membership in the selected runtime group is an explicit
authorization to invoke this pipeline with its shared provider credentials.
No world access is granted. Deployments that do not trust every group member
must use separate process-environment or `--secrets-dir` provisioning and are
outside this shared-operator policy.
Audita's proposal and validation configuration both reference
`AUDITA_LLM_API_KEY` by default. Narratio resolves that typed reference and
passes the value explicitly to the Audita child. Callers may still override
the existing Audita reference variables, but a custom split-key design also
requires an application boundary capable of forwarding both values and is not
promised by this feature.
Narratio's effective Notarius configuration names `OPENROUTER_API_KEY`, or a
caller-selected replacement, through `notarius.llm_api_key`. Narratio resolves
the named secret and forwards only that exact name and value to Notarius. It
does not infer a provider from Notarius configuration or forward unrelated
credentials.
Ordinary extraction sets `notarius.resume: true`. Notarius continues to own
checkpoint recording, identity, and storage beneath the configured
`/var/cache/notarius/checkpoints` root. Narratio requests reuse but does not
inspect the cache. The pipeline leaves Narratio's `notarius.chunk_cache` field
unset because the Notarius root configuration already selects `auto` at the
native owner. Forced extraction follows Narratio v2.1.0 behavior: resume is
omitted and the active chunk plan is refreshed without deleting unrelated
cache content.
Scriptorium continues to select credential names through its PromptKit
profiles. The Narratio process receives those names from the secret bootstrap,
and its existing adapter forwards the selected profile credential.
## Repository Ownership
- `../narratio` at immutable tag `v2.1.0` is the read-only application
authority for secrets bootstrap, typed Notarius credential forwarding,
checkpoint reuse, forced refresh, and subprocess redaction.
- `ansible-role-narratio` advances the application release and exposes the
three native Notarius fields through its generic field-specific interface.
It does not manage secret files or select suite policy.
- `ansible-role-dnd-pipeline` owns the conventional secrets directory, managed
credential mapping, suite-level Audita and Notarius reference coordination,
checkpoint-reuse selection, consumer documentation, and behavioral tests.
- `ansible-workspace-dnd` owns this roadmap, the settled MVP policy, progress,
and independent review record.
- The Audita, Notarius, and Scriptorium application roles remain unchanged;
they continue to own only their native configuration interfaces.
- The collection, asset, remaining application, and reference repositories
remain unchanged.
## Constraints and Settled Decisions
- Raw credential bytes never enter ordinary application YAML, Git-tracked
examples, workspace plans, or committed test fixtures.
- The role manages secret values only through `ansible.builtin.copy` content
or an equally direct secret-safe module operation with `no_log: true`.
- The conventional directory path is fixed because automatic Narratio
discovery depends on its relationship to the fixed root pipeline document.
- Credential filenames must match the environment-variable grammar accepted
by ConfigKit. Validation exists to prevent a caller-controlled key from
becoming a path outside the secrets directory.
- Credential values are written as supplied strings. ConfigKit and the typed
application reference own any nonempty-value requirement when a credential
is selected for use.
- An omitted mapping key is outside the role's ownership. Exact-directory
mirroring and deletion of unlisted files are intentionally excluded.
- The shared runtime group is an authorization group. Its members may read the
managed credentials; all other local users are denied access.
- The suite's group-readable credential policy deliberately differs from
Narratio's general single-user mode recommendation. ConfigKit does not
enforce those recommended modes, and the selected policy grants no world
access.
- Application adapters, rather than Ansible, own the secure transfer of loaded
values to child processes. Ansible does not create wrappers or reconstruct
the subprocess environment.
- Notarius's root configuration remains the single owner of ordinary
chunk-plan mode. Narratio's native `resume` field expresses the distinct
request to load compatible recorded checkpoints.
- Production convergence performs no provider call, credential validity test,
cache probe, content checksum bookkeeping, backup, or post-write reread.
## Simplest Viable Implementation Shape
The standalone Narratio role needs only a release update and three nullable
field-specific variables rendered through its existing template. It remains
generic and does not own credential files or suite policy.
The pipeline role needs one empty credential mapping, two Narratio Notarius
policy variables, coordinated Audita reference defaults, and ordinary
dependency wiring. Credential convergence consists of one directory task, one
validation loop, and one copy loop for supplied entries. Both secret-bearing
loops suppress their output.
Documentation and focused native integration coverage complete the public
interface. No state probe, handler, template assembly, manifest, wrapper,
directory scan, or role-private bookkeeping is required. The validation loop
is deliberate: the mapping key becomes a filesystem path, so rejecting
anything other than a valid environment-variable name protects the declared
destination boundary.
## Rationale and Alternatives
Narratio's native ConfigKit bootstrap is preferable to a shell wrapper or
service-specific environment file because every pipeline-loading command uses
the same application-owned behavior, whether invoked by the service account or
an authorized human operator. It also preserves the application's existing
environment-precedence and redaction rules.
A mapping is more ergonomic for inventory than a list of file objects because
the native identity of each entry is already its environment-variable name.
Omitted files remain unmanaged so consumers can combine Ansible-managed
credentials with another provisioning mechanism. Credential removal and
directory mirroring remain outside this feature until an operator-facing
lifecycle requirement is expressly selected.
Per-user `0700` directories would follow Narratio's general recommendation but
would require separate keys or an additional invocation convention for every
authorized human. The selected shared group already defines who may execute
the suite with shared state, so group-readable and world-inaccessible
credentials provide the intended operational model with less duplication.
Selecting Narratio checkpoint reuse completes the suite's earlier decision to
enable every available Notarius cache. Duplicating `chunk_cache: auto` in both
Narratio and Notarius configuration would add no ordinary behavior, so the
pipeline leaves the optional Narratio override unset and relies on each
application's documented ownership boundary.
## Acceptance Criteria
- The standalone Narratio role installs an explicitly selected v2.1.0 and can
render representative non-null and falsey values for
`narratio_notarius_llm_api_key`, `narratio_notarius_resume`, and
`narratio_notarius_chunk_cache` while omitting null values.
- The pipeline role selects Narratio v2.1.0 and pins the reviewed standalone
role revision that provides its native fields.
- The pipeline role creates `/usr/local/etc/narratio/secrets` with the selected
runtime ownership and suite credential-directory mode.
- `dnd_pipeline_secrets` defaults to an empty mapping and accepts valid
environment names with string values.
- Invalid names and non-string values fail before any destination outside the
declared secret directory can be constructed.
- Supplied entries converge to regular files with the selected runtime
ownership and mode `0640`; omitted names remain unmanaged.
- Credential values are suppressed from Ansible output and never appear in
application YAML, generated examples, native effective-configuration output,
test logs, or committed fixtures.
- Audita proposal and validation use `AUDITA_LLM_API_KEY` by default, and
Narratio's typed Audita field names that reference so the adapter explicitly
supplies the loaded value.
- Narratio's effective pipeline selects `OPENROUTER_API_KEY` through the typed
Notarius field and selects checkpoint resume for ordinary extraction.
- Narratio's optional chunk-cache override remains absent from the suite
configuration while Notarius's effective root configuration continues to
select `auto`.
- Scriptorium continues to receive the credential named by its selected
profile through the existing adapter behavior.
- A synthetic pipeline integration invocation with the relevant ambient
variables unset loads credentials through the conventional directory and
succeeds at native offline configuration validation as the service account
and one existing-group-member fixture.
- A distinctive synthetic secret never appears in captured integration output.
- The baseline credential application reports `changed=0` and `failed=0` on
an immediate identical repeat.
- Syntax checking, production-profile lint, and the complete standalone
Narratio and pipeline integration entry points pass.
- No live provider, WhisperX service, storage backend, model call, or
application cache execution occurs in default tests.
## Dependencies and Follow-up Work
- Features 0005, 0006, 0008, 0009, and 0010 are complete prerequisites.
- Narratio v2.1.0 at immutable tag `c45e042` satisfies the former typed
Notarius credential and cache-control prerequisite.
- The completed upstream feature request was removed from Narratio's active
roadmap during its v2.1.0 release cleanup; the release reference now owns the
delivered behavior.
- The standalone Narratio-role commit produced by this feature must be
available from its canonical Git origin before the pipeline's isolated
dependency test can use it.
- Collection assembly should follow this feature so the first assembled
collection packages a pipeline with complete credential delivery and cache
reuse.
- Storage and publishing policy may later add S3 or other credential reference
names to consumer inventory without changing the file-delivery mechanism.
- Operator selection, group-membership management, services, scheduling,
upgrades, removal, and external secret-manager integration remain separate
features.
## Potential Future Hardening
- Integrate a dedicated external secret manager or short-lived credential
broker.
- Support distinct per-operator secret directories for deployments that do
not treat runtime-group membership as shared credential authorization.
- Add explicit credential rotation orchestration and provider-side validity
checks.
- Add an explicit credential-removal or directory-lifecycle contract if an
operator need is identified.
- Add platform-specific mandatory-access-control policy for credential files.

View File

@@ -0,0 +1,304 @@
# Feature 0012: Assemble the D&D Collection
Status: done
## Summary
Turn the existing `ansible-collection-dnd` repository into a valid, buildable
`rakestraw.dnd` Ansible collection that exposes the independently developed
pipeline role as `rakestraw.dnd.pipeline`. The collection will carry a
self-contained snapshot of the pipeline role, publish the collection
dependencies Ansible can resolve natively, and provide one consumer bootstrap
manifest for the five Git-hosted application roles.
## Problem or Opportunity
The standalone application roles and the opinionated pipeline role are now
implemented and independently tested, but the collection repository still
contains only a placeholder README and repository metadata. A consumer cannot
build or install `rakestraw.dnd`, invoke the intended fully qualified role
name, or reproduce the reviewed combination of application-role dependencies
from that repository.
The pipeline role must remain independently developed, versioned, and usable.
At the same time, the collection artifact must contain the role it advertises;
it cannot depend on a sibling checkout, a symbolic link, or workspace-only
tooling at runtime. The assembly boundary therefore needs an explicit,
repeatable source-import convention and focused integration coverage of the
packaged result.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs collection metadata,
dependency declarations, documentation, and the preference for native
Ansible packaging behavior.
- [The testing house style](../../testing.md) governs behavior-oriented,
state-based validation and the avoidance of tests that merely restate file
layout or implementation details.
- [The MVP roadmap](../mvp.md) establishes the collection name, independently
released role repositories, Git-hosted application-role dependencies, and
the collection as the compatibility record for an assembled release.
- Features [0006](0006-pipeline-role-composition-foundation.md) through
[0011](0011-managed-pipeline-credential-delivery.md) define the pipeline
role behavior being assembled; this feature does not reopen those contracts.
## Scope
- Add valid Ansible Galaxy metadata for collection namespace `rakestraw`, name
`dnd`, development version `0.1.0`, the repository's existing license and
README, and its supported Ansible version.
- Declare the exact `ansible.posix` and `community.general` versions already
selected by the pipeline role as collection dependencies.
- Import the complete standalone pipeline-role repository into
`roles/pipeline` as a squashed Git subtree at an explicitly reviewed commit.
- Treat `ansible-role-dnd-pipeline` as authoritative: changes are made and
reviewed there first, then deliberately imported into the collection. Do
not edit role behavior directly beneath the collection's subtree prefix.
- Document the initial subtree import and subsequent update commands so the
source relationship is reproducible without custom tooling or private
knowledge.
- Ensure the standalone pipeline role's collection-facing documentation
distinguishes its standalone role name and invocation from
`rakestraw.dnd.pipeline` use without changing its public behavior.
- Add `meta/runtime.yml` with `requires_ansible: ">=2.18.0"`, matching the
implemented roles' supported baseline.
- Add one root `requirements.yml` that combines the five Git-hosted
application-role dependencies with the two collection dependencies needed
to bootstrap the assembled suite.
- Pin application roles to the exact reviewed commits already selected by the
standalone pipeline role during development. Keep the root bootstrap
manifest and the imported role's dependency manifests consistent.
- Configure collection builds to omit development-only content embedded in the
role subtree, including its integration suite, local Ansible configuration,
and nested dependency manifests. Retain operator-facing role documentation
and licensing in the source collection unless Ansible packaging requires
otherwise.
- Replace the collection's placeholder README with concise instructions for
dependency bootstrap, collection build and installation, FQCN invocation,
subtree provenance and updates, supported platform, and the distinction
between development commit pins and future released role tags.
- Add a focused collection integration suite that starts with isolated role
and collection paths, installs the root bootstrap manifest and the locally
built collection artifact, invokes `rakestraw.dnd.pipeline`, validates the
assembled pipeline through the applications' native configuration
interfaces, and verifies an immediate second application converges with no
reported changes.
## Non-goals
- Publishing the collection to Ansible Galaxy, Automation Hub, Gitea, or any
other registry.
- Creating the first collection release tag or application-role release tags.
- Replacing development commit pins with immutable role tags before those tags
exist.
- Vendoring any of the five standalone application roles into the collection.
- Moving authoritative pipeline-role development into the collection
repository or permitting collection-local role forks.
- Changing pipeline defaults, host convergence, application versions,
application configuration, asset deployment, credentials, or runtime
behavior.
- Adding collection plugins, modules, filters, playbooks, execution
environments, CI workflows, release automation, or a general-purpose sync
framework.
- Repeating every standalone pipeline integration scenario inside the
collection suite or asserting the exact contents of metadata and manifests
as an implementation snapshot.
- Supporting installation without network access. The collection artifact is
self-contained for the pipeline role, but its declared external role and
collection dependencies must still be made available to Ansible.
## Target End State
The collection repository has this durable shape:
```text
ansible-collection-dnd/
├── galaxy.yml
├── meta/
│ └── runtime.yml
├── requirements.yml
├── roles/
│ └── pipeline/ imported pipeline-role subtree
├── tests/
│ ├── converge.yml
│ ├── integration assembled-artifact behavior test
│ └── inventory
├── LICENSE
└── README.md
```
`ansible-galaxy collection build` produces a valid
`rakestraw-dnd-0.1.0.tar.gz` artifact. After the documented bootstrap installs
the root dependency manifest and the built artifact into clean Ansible paths,
a consumer can invoke:
```yaml
- name: Install and configure the D&D transcript pipeline
hosts: pipeline_hosts
roles:
- role: rakestraw.dnd.pipeline
```
The collection contains ordinary role files at `roles/pipeline`; it has no
runtime link to the standalone repository. Git history records that directory
as a squashed subtree import from `ansible-role-dnd-pipeline`. Maintainers make
pipeline changes in the standalone repository, validate and commit them there,
then update the collection subtree from the desired reviewed commit.
The root bootstrap manifest is the consumer-facing compatibility manifest for
development. It contains the same five application-role sources and reviewed
commit pins as the imported pipeline role, plus exact versions of
`ansible.posix` and `community.general`. The collection's Galaxy metadata also
declares those two collection dependencies because Ansible can resolve them as
native collection dependencies. This intentional duplication serves two
different installation boundaries and must remain consistent.
Development-only files may remain in the subtree source for faithful
provenance, but they are excluded from the built artifact. The collection's
own integration suite exercises the artifact rather than the repository role
directory, with role and collection paths isolated from ordinary user
installations.
## Repository Ownership
- `ansible-collection-dnd` owns collection metadata, the consumer bootstrap
manifest, the imported pipeline snapshot, collection-facing documentation,
build exclusions, and assembled-artifact integration coverage.
- `ansible-role-dnd-pipeline` remains authoritative for all pipeline-role code,
defaults, templates, dependency metadata, standalone documentation, and its
comprehensive integration suite. This feature changes only the wording
needed to document both standalone and collection use.
- The five standalone application-role repositories remain authoritative for
their roles and are read-only inputs to this feature.
- `campaigns` and `narratio-prompts` remain independently managed asset
repositories and are read-only integration inputs.
- `ansible-workspace-dnd` owns this feature roadmap, progress tracking, and the
later independent review record.
- Application source repositories and `rakestraw-ansible` remain unchanged.
## Constraints and Settled Decisions
- The collection is `rakestraw.dnd`; the bundled role's FQCN is
`rakestraw.dnd.pipeline`.
- A squashed Git subtree is the selected incorporation mechanism. It yields a
normal, self-contained collection artifact while preserving an auditable
upstream relationship and avoiding submodule checkout requirements,
symbolic links, manual copying, or custom synchronization state.
- The subtree prefix is `roles/pipeline`, and the standalone pipeline
repository remains the only place where role behavior is authored.
- The first development build uses collection version `0.1.0`. This version
enables ordinary Galaxy build and install validation but does not itself
authorize publication or establish a release tag.
- Development dependencies use exact reviewed commits. A later release pass
must replace all application-role commit pins with immutable role release
tags and revalidate the assembled artifact before publishing.
- Collection dependencies remain exactly `ansible.posix` 2.2.0 and
`community.general` 13.3.0, matching the existing reviewed pipeline
manifests.
- Galaxy metadata cannot install arbitrary standalone Git roles. The root
unified requirements manifest and documented bootstrap are therefore part
of the collection's public installation contract.
- The collection integration suite must not receive dependencies from the
developer's normal Ansible paths. Its success must demonstrate that the
documented manifest and built artifact are sufficient.
- The collection suite owns only the packaging boundary: buildability,
dependency bootstrap, FQCN resolution, representative assembled behavior,
native configuration acceptance, and convergence. Detailed pipeline feature
matrices remain in the standalone role's tests.
- The collection does not add probes, manifests, checksums, copied-file
comparisons, or private state to police the subtree. Git and the documented
subtree workflow are the provenance mechanism.
## Simplest Viable Implementation
Use Ansible's conventional collection layout and metadata directly. Import the
reviewed pipeline repository with ordinary `git subtree add --squash`, then
exclude only the subtree's development fixtures and nested bootstrap files
from Galaxy builds. No wrapper role, generated role, symbolic link, submodule,
or synchronization script is required.
Derive the root unified dependency manifest directly from the pipeline role's
two existing manifests. The only deliberate duplication is the collection
dependency declaration in `galaxy.yml`, because the artifact and the source
bootstrap have distinct native Ansible dependency interfaces.
Use one representative integration path: build into a temporary directory,
install dependencies and the artifact into isolated temporary Ansible paths,
apply `rakestraw.dnd.pipeline` using the same offline synthetic inputs already
proven by the standalone suite, run native application configuration
validation, and apply the play a second time to assert `changed=0` and
`failed=0`. This tests the behavior unique to collection assembly without
duplicating the standalone role's full test matrix.
## Rationale and Alternatives
A squashed subtree is preferable to a Git submodule because Ansible collection
archives require real role content and should build correctly from an ordinary
checkout without a second initialization step. It is preferable to a symbolic
link because archive behavior and installed collection paths would be fragile.
It is preferable to an unrecorded copy because subtree history retains the
source relationship and provides a standard update command. Squashing avoids
injecting the pipeline repository's entire development history into the
collection while still recording each reviewed import.
Moving the role permanently into the collection would simplify assembly, but
would discard the settled requirement that the suite role remain independently
developed, tested, versioned, and usable. A thin collection wrapper that
depends on `rakestraw.dnd_pipeline` would avoid source import but would not
actually bundle the role or satisfy the desired FQCN without adding another
runtime dependency layer.
Keeping one unified root requirements file gives consumers one bootstrap
command for both dependency kinds. Retaining the imported role's own
requirements files in source preserves standalone repository fidelity; build
exclusion prevents those nested development interfaces from confusing users
of the installed artifact.
## Acceptance Criteria
- The collection repository is recognized by `ansible-galaxy` as
`rakestraw.dnd` version `0.1.0` and builds successfully from a clean checkout.
- The built archive contains `roles/pipeline` and excludes the imported role's
development-only integration suite, local Ansible configuration, and nested
dependency manifests.
- The role content at `roles/pipeline` is traceable to a documented reviewed
commit of `ansible-role-dnd-pipeline` through the repository's squashed
subtree history.
- The standalone pipeline README accurately documents both
`rakestraw.dnd_pipeline` and `rakestraw.dnd.pipeline` consumption without
changing role behavior.
- `meta/runtime.yml` selects Ansible 2.18 or newer, and Galaxy metadata declares
the exact two collection dependencies used by the pipeline.
- The root bootstrap manifest contains all five standalone application roles
at the same reviewed commits used by the imported pipeline role and the
exact two required collections.
- Collection documentation provides sufficient commands to install the
bootstrap dependencies, build and install the artifact, invoke the pipeline
FQCN, and update the subtree from a future reviewed pipeline commit.
- The integration suite starts with isolated Ansible role and collection
paths, installs only the declared bootstrap inputs and built artifact, and
resolves `rakestraw.dnd.pipeline` without access to a sibling role checkout.
- The representative assembled deployment passes the applications' native
configuration validation and an immediate identical second run reports
`changed=0` and `failed=0`.
- Existing standalone pipeline-role validation continues to pass after its
documentation-only change.
- No application role, application source, asset behavior, or pipeline host
convergence behavior changes as part of this feature.
## Dependencies and Follow-up Work
- Features 0001 through 0011 and their reviewed role commits are prerequisites.
- A subsequent release feature must create immutable role tags, replace
development commit pins, select the release collection version, validate the
tagged combination, create release notes and tags, and publish or distribute
the artifact.
- CI automation may later run the collection integration suite after a local,
repeatable workflow exists.
## Potential Future Hardening
- Sign collection artifacts or publish checksums and software bills of
materials when a distribution threat model requires them.
- Automate subtree provenance checks and dependency-pin synchronization if
manual collection updates become frequent enough to justify that machinery.

View File

@@ -0,0 +1,285 @@
# Feature 0013: Publish the First Coordinated Suite Release
Status: done
## Summary
Publish the reviewed D&D pipeline as the first immutable, remotely installable
release of its five application roles, standalone pipeline role, and
`rakestraw.dnd` collection. The release establishes `v0.1.0` tags in the
projects' public Gitea repositories, replaces development commit pins with
those role tags, and makes the built `rakestraw-dnd-0.1.0.tar.gz` collection
artifact available from the collection's Gitea release.
## Problem or Opportunity
The application roles, pipeline role, and collection have been implemented,
reviewed, and tested as one compatible suite. Their current dependency
manifests still select application roles by development commit, however, and
none of the seven Ansible repositories has an immutable release tag. The
collection documentation consequently describes a development build rather
than a published release, and a consumer cannot bootstrap the reviewed suite
entirely from named releases and a published collection artifact.
The initial release should turn the existing reviewed compatibility set into a
durable public installation boundary without changing application behavior or
introducing release automation. It must prove that the release is consumable
from Gitea alone rather than from sibling repositories or unpublished local
artifacts.
## Governing Policies
- [The Ansible house style](../../ansible.md) governs dependency manifests,
collection packaging, and concise consumer documentation.
- [The testing house style](../../testing.md) governs release validation. The
feature reuses behavior-oriented repository suites and adds only validation
specific to the remote publication boundary.
- [The planning policy](../../planning.md) governs the cross-repository
implementation and review workflow.
- [The MVP roadmap](../mvp.md) defines independent role releases, immutable
release pins, the collection as the compatibility record, and public Gitea
as the release source.
- [Feature 0012](0012-collection-assembly.md) defines the authoritative
pipeline subtree, unified consumer manifest, and assembled-artifact testing
boundary that this feature releases without redesigning.
## Scope
- Publish `v0.1.0` as the initial release of each standalone application role:
`rakestraw.audita`, `rakestraw.narratio`, `rakestraw.notarius`,
`rakestraw.seriatim`, and `rakestraw.scriptorium`.
- Point those application-role tags at the exact reviewed commits already
selected by the pipeline compatibility manifest. No application-role code
or default changes are part of release preparation.
- Replace the five development commit pins in the authoritative pipeline
role's root dependency manifest with the corresponding immutable `v0.1.0`
role tags.
- Update the pipeline documentation to describe the released dependency pins
and its standalone installation path without changing its role interface or
runtime behavior.
- Validate and publish `v0.1.0` of the standalone pipeline role after its
release manifest and documentation are complete.
- Import the published pipeline `v0.1.0` state into the collection's
`roles/pipeline` subtree using the established remote-only, squashed subtree
workflow.
- Replace the collection's five application-role commit pins with the same
`v0.1.0` tags used by the authoritative pipeline role, retaining the exact
`ansible.posix` and `community.general` version pins already selected.
- Retain collection version `0.1.0` in `galaxy.yml`, update collection
documentation from development-build language to released installation
instructions, and identify the release as the compatibility record for the
seven selected component versions.
- Create and push public, immutable `v0.1.0` tags for all seven Ansible
repositories.
- Build `rakestraw-dnd-0.1.0.tar.gz` from the tagged collection content and
create a concise public Gitea `v0.1.0` collection release whose attachment
is that exact artifact.
- Validate that a clean consumer can obtain the tag-pinned dependency manifest
and collection archive from their public Gitea URLs, install them into
isolated Ansible paths, invoke `rakestraw.dnd.pipeline`, and obtain an
immediate clean repeat.
- Record the completed release and its immutable compatibility set in the
workspace status and durable release-facing documentation.
## Non-goals
- Changing application versions, role defaults, pipeline configuration,
filesystem policy, credentials, assets, or deployed runtime behavior.
- Synchronizing future versions of independently released roles. The shared
initial version is a convenient baseline, not a lockstep release policy.
- Publishing the collection to Ansible Galaxy, Automation Hub, or another
package registry.
- Vendoring the five application roles into the collection or changing the
selected pipeline subtree model.
- Adding CI/CD, a release script, a changelog generator, dependency-update
automation, or a general-purpose release framework.
- Adding tests that snapshot manifest text, tag names, defaults, task traces,
or other implementation details. Release validation should exercise the
public installation and deployed behavior.
- Signing tags or artifacts, generating checksums or software bills of
materials, mirroring dependencies, or adding other supply-chain hardening.
- Defining upgrade, downgrade, removal, scheduling, or optional human-operator
account management.
## Target End State
Each public application-role repository has an immutable `v0.1.0` tag for the
exact role revision already reviewed as part of the assembled suite:
| Role | Released revision |
| --- | --- |
| `rakestraw.audita` | `66ebea9a47ce82bfdbdc5e2855f3dfaaff8e2a16` |
| `rakestraw.narratio` | `292d8669e7aad5cfe80b0c469d22b6177e8cf0f1` |
| `rakestraw.notarius` | `14a38e04e35ef524d6a97fa7fb5a04981a0a2161` |
| `rakestraw.seriatim` | `e08c63c0b078658bdfa2d10a2e6e1e4f9372a075` |
| `rakestraw.scriptorium` | `8b4c86e48e7d8655e479b26dc510bf01683a0c8f` |
The standalone pipeline role has its own immutable public `v0.1.0` tag. Its
role dependency manifest selects all five application roles with
`version: v0.1.0`, and its collection dependency manifest retains
`ansible.posix` 2.2.0 and `community.general` 13.3.0. The pipeline release is
independently installable under `rakestraw.dnd_pipeline`.
The collection's `roles/pipeline` subtree is a faithful squashed import of the
published pipeline `v0.1.0` release. Its consumer-facing `requirements.yml`
contains the same five role tags and collection versions as the standalone
pipeline manifests. `galaxy.yml` remains version `0.1.0`, and the collection
repository has an immutable `v0.1.0` tag and corresponding public Gitea
release to carry the built artifact.
The collection release includes the archive produced from that released tree,
named `rakestraw-dnd-0.1.0.tar.gz`. Its public release notes identify the exact
five application-role versions, pipeline-role version, native collection
dependencies, supported platform, and consumer bootstrap steps. A consumer
can fetch the tagged manifest and archive through public Gitea URLs and
install the suite without access to this development workspace.
## Repository Ownership
- The five standalone application-role repositories own their respective
`v0.1.0` tags. Their reviewed role content remains unchanged by this
feature.
- `ansible-role-dnd-pipeline` owns its tag-pinned role manifest, standalone
release documentation, and `v0.1.0` tag.
- `ansible-collection-dnd` owns the released pipeline subtree, unified
tag-pinned consumer manifest, collection release documentation, collection
tag, built artifact, and Gitea release attachment.
- `ansible-workspace-dnd` owns this roadmap, cross-repository compatibility
record, active implementation plan, progress tracking, and independent
release review.
- The application source repositories, campaign repository, prompt-library
repository, and `rakestraw-ansible` are unchanged release inputs.
## Constraints and Settled Decisions
- Public repositories beneath
`https://gitea.maximumdirect.net/eric/` are the authoritative publication
channel for this release.
- Every Ansible repository uses initial release tag `v0.1.0`. The collection's
Galaxy version remains the corresponding unprefixed `0.1.0`, as required by
collection metadata and artifact naming.
- Tags are immutable release boundaries. A release candidate must be validated
before its tag is created and pushed; published tags must not be moved to
repair a failed release.
- The five application-role tags identify the exact reviewed commits shown in
the target end state. Release metadata must not create otherwise unnecessary
commits in those repositories.
- Released role dependency manifests use tag names, not branches or commit
hashes. Application repositories remain independently versioned after this
shared initial baseline.
- The pipeline repository remains authoritative. Its release must be pushed
to Gitea before the collection imports the `v0.1.0` revision through the
documented remote-only subtree command.
- The collection tag identifies the exact source tree from which the attached
artifact is built. The attached file must not be rebuilt from a later or
dirty tree while retaining the same version.
- The public collection release attachment is the selected binary publication
interface. The repository tag remains the source publication interface.
- Consumer validation must not use sibling checkouts, normal user Ansible
paths, preinstalled project roles, or an unpublished local collection
archive.
- The collection's Gitea release description and existing repository
documentation are
sufficient for the initial release. This feature does not introduce
repository-local changelog files solely to duplicate those notes.
## Simplest Viable Implementation
Use ordinary Git tags, one collection Gitea release, existing Ansible
dependency manifests, the established subtree command, and `ansible-galaxy
collection build`. The five application roles need validation and tags only.
The pipeline and collection need small manifest and documentation changes
before their respective release tags are created.
Reuse the existing repository-local integration entry points as release gates.
The collection integration suite already exercises isolated dependency
bootstrap, archive construction and installation, FQCN resolution, native
application behavior, and clean repeated convergence. Adapt its inputs only as
necessary to consume the release tags, and use a focused final smoke path to
download the published manifest and attached archive from Gitea. Do not add a
second release framework or duplicate the detailed behavior matrices owned by
the standalone repositories.
Publication is intentionally manual for the first release. The work does not
yet justify release scripts, workflow files, persistent staging state, or a
new packaging service.
## Rationale and Alternatives
Immutable role tags give consumers meaningful versions while preserving the
settled model of independently released repositories. Publishing only commit
hashes would be reproducible but would not establish the named release
contract required by the MVP. Publishing branches would not be immutable.
Using `v0.1.0` for every initial role and the collection makes the first
compatibility baseline easy to understand. Future role releases remain
independent, and future collection releases record whatever combination is
then supported; no synchronized-version policy is implied.
Attaching the Galaxy-built archive to the public Gitea collection release
provides a direct installation artifact without introducing another registry.
Requiring consumers to clone and build the collection would expose unnecessary
development steps, while publishing to Ansible Galaxy or Automation Hub would
add an unselected distribution channel and account lifecycle.
Manual publication is appropriate for one initial release and keeps the
release contract visible. Automation can be considered after repeated release
work demonstrates a stable process worth encoding.
## Acceptance Criteria
- Each application-role repository advertises a public, immutable `v0.1.0`
tag at the exact reviewed revision listed in this roadmap.
- Each application role's existing syntax, lint, integration, and clean-repeat
validation passes for the candidate being tagged; no role behavior is
changed merely to create the release.
- The pipeline role's released manifest selects all five application roles by
`v0.1.0`, and its collection dependency versions remain unchanged.
- The pipeline's existing validation installs its application-role
dependencies from the public Gitea tags, exercises the role through its
public interface, and passes its immediate clean repeat.
- The pipeline repository advertises a public, immutable `v0.1.0` tag at the
validated release commit.
- The collection subtree matches the published pipeline `v0.1.0` tree outside
repository-specific Git metadata and records the remote Gitea import in Git
history.
- The collection's root manifest uses the same five `v0.1.0` application-role
pins and exact native collection versions as the released pipeline role.
- `ansible-galaxy collection build` from the collection release candidate
produces `rakestraw-dnd-0.1.0.tar.gz`, and the existing artifact-boundary
exclusions remain effective.
- The collection's existing integration suite passes against the release
candidate, including isolated bootstrap, installed-artifact FQCN use,
representative native application checks, and immediate `changed=0` and
`failed=0` convergence.
- The collection repository advertises a public, immutable `v0.1.0` tag and
matching Gitea release. The archive attached to that release is the artifact
built from the tagged tree.
- A clean remote-only smoke validation downloads the public tag-pinned
manifest and public collection attachment, installs into isolated paths,
resolves `rakestraw.dnd.pipeline`, and completes with a clean immediate
repeat without referencing any sibling repository or unpublished artifact.
- Release-facing documentation no longer describes collection `0.1.0` or the
role release tags as future or unpublished, and it gives the complete public
Gitea installation path without requiring the development workspace.
- All participating repositories are clean, their release commits and tags
are present upstream, and workspace status records the published
compatibility baseline.
## Dependencies and Follow-up Work
Feature 0012 and its remediation must remain complete. Credentials capable of
pushing commits and tags and creating the public collection Gitea release and
attachment must be available during implementation.
Potential later features include release automation, publication to an Ansible
registry, independently versioned follow-up releases, optional suite-level
operator membership management, and defined upgrade, downgrade, or removal
behavior. None is required for the initial release.
## Potential Future Hardening
- Signed Git tags or release artifacts.
- Published checksums, provenance attestations, or software bills of
materials.
- Automated verification and publication in a controlled CI environment.

View File

@@ -0,0 +1,240 @@
# Feature 0014: Enroll Existing Pipeline Operators
Status: done
## Summary
Let consumers name existing human accounts that the D&D pipeline role should
add to its shared runtime group. The interface is empty by default, manages
membership additively, and leaves account creation and removal outside the
role.
## Problem or Opportunity
The pipeline's shared filesystem and credential policy already supports
invocation by the dedicated `narratio` service account or by a human member of
the selected runtime group. The role does not yet select human operators or
manage their membership. Consumers must currently repeat a small
`ansible.builtin.user` task beside the role even though group enrollment is a
natural suite-level access choice.
The role must not silently become a general account-management interface.
Human account identity, login policy, credentials, home directories, and
removal remain host or organization concerns. The pipeline needs only a
concise way to enroll explicitly selected existing accounts in the group that
already defines pipeline authorization.
## Governing Policies
- [The Ansible house style](../../ansible.md) requires the smallest direct
desired-state implementation and permits state inspection only when its
result is independently required.
- [The testing house style](../../testing.md) requires a representative
public-interface test of deployed behavior and immediate clean convergence,
without retesting `getent` or `user` module internals.
- [The MVP roadmap](../mvp.md) defines the runtime group as the shared
operator and credential-authorization boundary.
- [Feature 0009](0009-shared-pipeline-filesystem-and-execution.md) establishes
the service-user and human-group-member execution model.
- [Feature 0011](0011-managed-pipeline-credential-delivery.md) establishes
that runtime-group membership authorizes access to the suite's shared
credentials.
- [Feature 0012](0012-collection-assembly.md) makes the standalone pipeline
repository authoritative and requires reviewed changes to enter the
collection through its public Gitea subtree source.
## Scope
- Add `dnd_pipeline_operator_users`, a list of existing account names that
defaults to an empty list.
- Declare the variable as a list of strings in the pipeline role's argument
specification.
- Require every selected account to exist before changing any selected
account's group membership.
- Add each selected account to `dnd_pipeline_runtime_group` with additive
supplementary-group semantics.
- Preserve the existing account, its primary group, and all other
supplementary groups.
- Leave omitted accounts and memberships unmanaged.
- Document the existing-account contract, additive behavior, authorization
consequence, and need to begin a new login session before newly granted
supplementary membership is visible to a long-lived user session.
- Adapt the existing pipeline integration fixture to exercise enrollment
through the new public variable and retain its representative configuration,
secret-access, shared-cache, and clean-repeat behavior.
- Import the reviewed, pushed pipeline commit into the collection through the
established squashed subtree workflow and validate the assembled artifact.
## Non-goals
- Creating, deleting, locking, or otherwise managing human accounts.
- Managing UIDs, primary groups, passwords, SSH keys, shells, home
directories, sudo access, or login policy.
- Removing a user from the runtime group when the user is omitted from the
list or removed from a later inventory value.
- Managing external identity-provider or directory-service membership.
- Adding per-user access controls, separate credential sets, or a second
operator group.
- Changing the `narratio` service account, runtime group, filesystem modes,
ACL policy, credential policy, or application configuration.
- Adding handlers, sidecar state, membership snapshots, post-change
verification, or a custom account-management abstraction.
- Publishing a new pipeline-role or collection release as part of this
implementation.
## Target End State
The pipeline role exposes this optional interface:
```yaml
dnd_pipeline_operator_users:
- eric
- alice
```
The default is `[]`, so existing consumers retain their current behavior. If
the list is nonempty, every named account must already exist on the managed
host. The role fails before its enrollment task when any selected account is
absent; it does not create a partially specified account as a side effect.
Each existing selected account is an additive member of
`dnd_pipeline_runtime_group`. Existing primary and supplementary memberships
remain intact. Membership in that group grants the pipeline access already
defined by Features 0009 and 0011, including shared writable runtime roots and
group-readable suite credentials. Existing login sessions may need to be
restarted before the operating system exposes newly granted supplementary
membership.
Removing a name from `dnd_pipeline_operator_users` does not revoke membership.
Account and access removal require an explicit lifecycle policy and remain
separate work.
The collection's `rakestraw.dnd.pipeline` role contains the same reviewed
interface through a squashed import from the authoritative public pipeline
repository. The published `v0.1.0` release remains unchanged until a later
release feature selects and validates a new version.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the public variable, existing-account
prerequisite, additive enrollment, operator documentation, and detailed
behavioral integration coverage.
- `ansible-collection-dnd` owns the faithful subtree import and its existing
assembled-artifact validation boundary. It does not independently
reimplement or duplicate the pipeline behavior test.
- `ansible-workspace-dnd` owns this roadmap, the settled MVP decision, active
implementation plan, status, and review record.
- The standalone application roles, application sources, asset repositories,
and `rakestraw-ansible` remain unchanged.
## Constraints and Settled Decisions
- The public interface is a simple list of usernames, not a mapping of account
definitions. A richer structure would imply ownership of account creation
and login policy that this feature expressly excludes.
- All selected accounts must exist before enrollment begins. A single
`ansible.builtin.getent` loop over the `passwd` database is justified because
`ansible.builtin.user` with `state: present` would otherwise create a missing
account. No registered fact, separate assertion, or post-enrollment query is
required.
- The enrollment task uses `ansible.builtin.user` with the selected runtime
group and `append: true`. The module owns membership convergence; the role
does not inspect or reconstruct current group lists.
- The enrollment task uses `become: true`. The account-existence lookup does
not require elevation.
- The runtime group continues to be created by the existing Narratio role
dependency before the pipeline role's ordinary tasks execute.
- Empty input naturally skips both loops. No separate conditional, fact, or
branching task is needed.
- Omission is unmanaged, not absent. The feature adds access but does not
define revocation or exact-list reconciliation.
- No username grammar stricter than the managed host's account database is
introduced. The `getent` lookup and `user` module retain ownership of their
native input and error handling.
## Simplest Viable Implementation
Add the empty-list default and matching argument-spec entry. Add one
`ansible.builtin.getent` task that loops over the selected names with database
`passwd` and relies on its default missing-key failure, followed by one
privileged `ansible.builtin.user` task that loops over the same names, selects
`dnd_pipeline_runtime_group`, and uses `append: true`.
Replace the README's consumer-owned membership example with the role variable
and its exact ownership boundary. In the existing integration driver, create
the temporary operator without `narratio` membership before the first role
application, pass that account through `dnd_pipeline_operator_users`, and
retain the existing native configuration and shared-access exercises. Do not
add a missing-user test, inspect `/etc/group`, assert module return data, or
create a second operator scenario.
After the authoritative pipeline change is committed, validated, and pushed,
use the documented public Gitea `git subtree pull --squash` workflow to import
that exact commit into `ansible-collection-dnd`. Run the collection's existing
artifact-boundary integration suite without expanding its detailed feature
matrix.
## Rationale and Alternatives
Keeping membership entirely in each consumer play would avoid two role tasks,
but it leaves every deployment to reproduce access policy already owned by the
suite. An empty-by-default list adds the ergonomic path without affecting
consumers that prefer external membership management.
Passing complete account definitions to the pipeline role would permit it to
create users, but it would also require defaults and policy for homes, shells,
authentication, IDs, and account removal. Those concerns are not pipeline
requirements and belong to host identity management.
Calling `ansible.builtin.user` without first checking existence would be more
compact but would create missing accounts with implicit properties. The
`getent` lookup is therefore independently required to enforce the selected
ownership boundary; it is not defensive re-verification of state already
owned by another module.
Exact-list reconciliation would make removal declarative, but omission has
not been selected as revocation and could remove access managed elsewhere.
Additive enrollment is the smaller and safer contract until lifecycle policy
is designed explicitly.
## Acceptance Criteria
- `dnd_pipeline_operator_users` defaults to an empty list and is declared as a
list of strings in the public argument specification.
- An empty list introduces no account or membership change.
- Every explicitly selected account must already exist, and a missing account
causes convergence to fail before the enrollment task can create or modify
any selected account.
- Each selected existing account is added to
`dnd_pipeline_runtime_group` additively without replacing its other groups.
- Omitted accounts and prior memberships remain unmanaged.
- The role uses only one account-existence task and one enrollment task; it
adds no handler, registered fact, assertion layer, command, private state,
or post-change verification.
- The pipeline documentation explains the variable, existing-account
prerequisite, additive non-removal behavior, group authorization boundary,
and login-session caveat.
- The existing temporary-operator integration scenario enrolls its fixture
through the public variable, demonstrates representative pipeline access,
and the immediate identical second role application reports `changed=0`
and `failed=0`.
- Syntax checking, production-profile lint, the complete standalone pipeline
integration suite, and `git diff --check` pass.
- The exact reviewed pipeline commit is pushed to public Gitea before the
collection imports it.
- The collection subtree contains the reviewed pipeline change through the
documented remote-only squashed import, and the existing collection
integration suite passes against the built and installed artifact.
- No application repository, asset repository, release tag, published
artifact, application configuration, filesystem policy, or credential value
changes.
## Dependencies and Follow-up Work
Features 0009, 0011, 0012, and 0013 are prerequisites. The completed Feature
0013 workspace and collection closeout commits should be pushed before the
implementation sprint begins so local and remote baselines agree.
Upgrade, downgrade, account revocation, exact-membership reconciliation,
application removal, and publication of a release containing this feature
remain separate future work.

View File

@@ -0,0 +1,424 @@
# Feature 0015: Enable D&D S3 Storage and Publishing
Status: done
## Summary
Make the D&D pipeline operational with Narratio's current S3 storage,
publication, caching, cleanup, and restore capabilities. The pipeline role
will select the established Backblaze B2 destination, reference two typed
object-storage credentials delivered through its existing secrets directory,
publish the useful transcript and D&D artifact outputs, and retain maximum S3
audio caching.
The standalone Narratio role already exposes Narratio v2.1.1's complete
configuration surface for this behavior. This feature supplies D&D suite
policy through that existing interface; it does not add another storage
implementation or credential mechanism.
## Problem or Opportunity
The pipeline role currently installs Narratio v2.1.0 and configures the full
processing graph, but deliberately leaves Narratio storage and publishing at
their application-level defaults. Its README consequently describes storage,
publishing, and end-to-end external execution as deferred. The resulting suite
can validate configuration and process local state, but it does not select the
remote archive or publish the outputs needed for an operational deployment.
Narratio v2.1.0 also rejected a valid publish list when a rule explicitly set
`required` while omitting a derivable `dest`. Narratio v2.1.1 corrects that
resolution bookkeeping defect without changing the publish schema or
destination rules. This feature therefore advances the pipeline application
pin to v2.1.1 and retains explicit suite-owned requiredness together with
native destination derivation.
The prior test-machine configuration records the intended Backblaze B2
endpoint, bucket, prefix, credential names, publication set, and post-publish
workspace cleanup. Narratio's current contract has since replaced the legacy
credential field names and secrets configuration with ConfigKit typed
references and a conventional sibling `secrets/` directory. The Ansible suite
already implements that new credential-delivery boundary for Audita and
Notarius, so S3 needs only to join the same path.
## Governing Policies
- [The Ansible house style](../../ansible.md) requires suite policy to flow
through the standalone role's field-specific interface and optional fields
to remain application-owned unless the suite deliberately selects them.
- [The testing house style](../../testing.md) requires representative
public-interface and native-application validation without duplicating AWS
SDK, ConfigKit, or Ansible module behavior.
- [The MVP roadmap](../mvp.md) makes the pipeline role responsible for
cross-application configuration and end-to-end validation.
- [Feature 0011](0011-managed-pipeline-credential-delivery.md) establishes the
managed Narratio secrets directory and typed credential-forwarding policy.
- [Feature 0012](0012-collection-assembly.md) makes the standalone pipeline
repository authoritative and imports reviewed changes through public
Gitea.
- [Feature 0016](0016-deploy-dnd-pipeline-to-pipeline-dnd.md) consumes this
feature's reviewed interface for the first real-host deployment.
## Scope
- Advance the suite's Narratio application version from `v2.1.0` to the
backward-compatible `v2.1.1` bugfix release.
- Add suite-owned pipeline variables for the selected Narratio workspace,
S3, cache, and publish settings.
- Select the S3 backend with these D&D deployment defaults:
| Setting | Suite default |
| --- | --- |
| Endpoint | `https://s3.us-east-005.backblazeb2.com` |
| Bucket | `rakestraw-assets` |
| Root prefix | `dnd` |
| Region | `us-east-1` |
| Force path style | `true` |
| Access-key reference | `OBJECT_STORAGE_KEY_ID` |
| Secret-key reference | `OBJECT_STORAGE_KEY` |
- Pass the two credential reference names to the standalone Narratio role.
Their values use the existing `dnd_pipeline_secrets` map and managed
`/usr/local/etc/narratio/secrets/` directory.
- Enable S3 audio caching explicitly so the suite retains Narratio's maximum
available audio reuse.
- Enable run publication and publish these complete native output rules:
| Source | Required |
| --- | --- |
| `narratio.transcript.final` | `true` |
| `narratio.transcript.final_trimmed` | `true` |
| `narratio.transcript.final_markdown` | `true` |
| `narratio.transcript.final_trimmed_markdown` | `true` |
| `narratio.artifact.session_recap` | `true` |
| `narratio.artifact.hostile_rumors` | `true` |
| `narratio.artifact.deranged_rumors` | `false` |
- Let Narratio derive each destination from the built-in transcript path or
configured artifact output path rather than duplicating those paths in the
publish list.
- Enable workspace cleanup only after Narratio records successful run
publication. Leave spool-audio deletion under Narratio's existing default
because the suite has selected no policy requiring source-audio removal.
- Keep the production and `testing` profile storage and publishing behavior
identical. The existing overlay remains limited to model-profile selection.
- Document the four credentials normally required by the operational suite:
`AUDITA_LLM_API_KEY`, `OPENROUTER_API_KEY`,
`OBJECT_STORAGE_KEY_ID`, and `OBJECT_STORAGE_KEY`.
- Document the operator-visible publication, restore, S3-session-audio, lock,
caching, and cleanup capabilities enabled by the selected configuration,
while linking Narratio's canonical CLI and operations documentation for
command details.
- Preserve every accepted Notarius lane as its existing
`narratio.extraction.<output_key>` source. Future Narratio artifact
definitions can consume those sources during analyze without first making
the extraction lanes separate published outputs.
- Adapt the existing pipeline integration scenario to resolve synthetic S3
credentials and validate one explicitly supplied representative storage and
publishing configuration through Narratio's native interface without
contacting object storage.
- Import the reviewed public pipeline commit into the collection through the
established squashed subtree workflow, adapt the collection's artifact-level
fixture to supply the added credential names, and validate the assembled
artifact.
## Non-goals
- Implementing an S3 client, publication engine, remote commit format,
restore mechanism, publish-lock mechanism, or audio cache in Ansible.
Narratio owns all of those behaviors.
- Placing credential values in role defaults, templates, documentation,
tests, ordinary inventory, or the generated pipeline configuration.
- Adding a second secret-delivery mechanism, environment wrapper, service
unit, credential synchronizer, or AWS configuration-file manager.
- Managing Backblaze buckets, object lifecycle policy, application keys,
retention policy, versioning, encryption, quotas, or network access.
- Managing per-session `session.yml` files or selecting local versus S3 audio
input for an individual session.
- Running a paid or networked publication test from a repository-local test
suite. Feature 0016 owns the representative live end-to-end exercise.
- Publishing every Notarius extraction lane as a named current output. The
lanes remain available as analyze inputs independently of publication; stable
remote destinations require an explicit operator need.
- Setting Narratio's optional `notarius.chunk_cache` override. The managed
Notarius configuration remains the single owner of its ordinary `auto`
cache policy, and Narratio v2.1 already requests refresh for forced
extraction.
- Adding notification providers. Narratio v2.1 supports only its existing
`noop` notification mode.
- Releasing new role or collection versions as part of this implementation.
- Modifying Narratio, ConfigKit, or the standalone Narratio role. Narratio
v2.1.1 is an already published prerequisite, and the existing generic role
can install the selected application tag through `narratio_version`.
## Target End State
The standalone pipeline role exposes these suite variables with the selected
defaults:
```yaml
dnd_pipeline_narratio_version: v2.1.1
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
```
Each value is declared in the pipeline argument specification and passed
directly to its corresponding `narratio_*` variable in the pipeline role's
Narratio dependency. Narratio's existing root template renders the native
configuration. No new pipeline fragment or production task is required.
The ordinary generated configuration contains only the credential names:
```yaml
storage:
backend: s3
s3:
access_key_id: OBJECT_STORAGE_KEY_ID
secret_access_key: OBJECT_STORAGE_KEY
```
Consumers supply the two values beside the existing model-provider values
through encrypted inventory:
```yaml
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 }}"
```
The example defines references only; no roadmap, role, or test contains real
credential values. The existing credential task writes the selected entries
with the suite's established group-authorized secret modes. Omitted map keys
remain unmanaged, as defined by Feature 0011.
With valid credentials, Narratio can accept either local or S3 audio selected
by each session file, cache S3 audio beneath `/var/cache/narratio`, publish an
immutable run and the selected stable outputs, use remote publication locks,
restore committed state, and clean the published workspace. These are native
Narratio commands and lifecycle rules rather than additional Ansible tasks.
The ten accepted Notarius outputs continue to enter Narratio's artifact
catalog as `narratio.extraction.*` sources. Analyze-stage Scriptorium artifacts
may reference those sources directly in their input mappings. Feature 0015
does not yet add such artifact definitions, but its publication choices do not
remove, rename, or constrain this future composition path.
## Repository Ownership
- `ansible-role-dnd-pipeline` owns the D&D suite variables, opinionated
defaults, dependency mappings, consumer documentation, and representative
integration scenario.
- `ansible-role-narratio` remains the generic owner of installation and native
pipeline rendering. Its reviewed `v0.1.0` role interface is compatible with
Narratio v2.1.1 and already covers every
configuration field required by this feature and should remain unchanged.
- `ansible-collection-dnd` owns the faithful pipeline subtree import, the
unified consumer dependency manifest, and artifact-boundary validation.
- `ansible-workspace-dnd` owns this roadmap, the later implementation plan,
status, and independent review record.
- `narratio` v2.1.1 is the released compatibility prerequisite and a read-only
source of storage, publication, credential, caching, cleanup, restore, and
CLI contracts during this implementation.
- `rakestraw-ansible` remains unchanged until Feature 0016 consumes this
interface on `pipeline-dnd`.
## Constraints and Settled Decisions
- The S3 endpoint, bucket, prefix, region, and path-style values are deliberate
D&D suite defaults. They are ordinary variables and remain overrideable by
inventory.
- Credential references are also policy defaults, but credential values have
no defaults. Operators must supply matching entries through
`dnd_pipeline_secrets` or another environment source supported by Narratio.
- The two credential-reference variables are nullable as a pair. Setting both
to `null` omits the references and preserves Narratio's AWS SDK provider-chain
path; configuring only one remains invalid under Narratio's native contract.
- The role does not assert that the secrets map contains particular keys.
Narratio's native loader owns typed-reference resolution, and external
environment values remain a supported higher-precedence source.
- `dnd_pipeline_narratio_publish_outputs` is one complete native list. A caller
replacing it assumes responsibility for the entire selected publication
set; the role does not merge rules.
- Publish destinations remain omitted where Narratio can derive them. The
configured source identity and artifact output path remain the single source
of truth.
- Narratio v2.1.1 is the minimum application version for this feature because
it preserves destination derivation when `required` is explicit. Do not work
around older behavior by duplicating destinations or omitting deliberate
requiredness.
- Workspace cleanup is gated by Narratio's own successful-publication
evidence. Ansible does not independently inspect remote state or remove
runtime content.
- S3 audio caching is enabled, and ordinary cleanup preserves the cache.
Explicit operator cache clearing remains a Narratio CLI operation.
- The testing profile does not silently disable Notarius, storage,
publication, cleanup, or credentials. It continues to differ only in the
already selected inexpensive Scriptorium model profile.
- S3 storage also enables Narratio's native restore and publication-lock
commands without another configuration surface. Ansible documentation may
describe availability but must not duplicate Narratio's detailed operating
manual.
- Notarius extraction-source availability and remote publication are separate
concerns. Analyze consumes `narratio.extraction.*` sources from the accepted
extraction catalog; `publish.outputs` selects only which sources also receive
stable published destinations.
## Simplest Viable Implementation
Advance `dnd_pipeline_narratio_version` to v2.1.1. Add the selected variables to
the pipeline defaults and argument specification, then map them into the
existing `rakestraw.narratio` dependency. Update the pipeline README to document
the policy, credential names, complete-list replacement semantics, and native
capabilities now available. Do not add a template, task, handler, fact, probe,
or storage-specific validation layer.
In the existing pipeline integration driver, extend the synthetic secrets map
with object-storage values and explicitly supply representative S3 and publish
variables. Use `narratio config validate` and its secret-safe effective
configuration output to prove that the public inputs compose into a valid
configuration. Retain the immediate clean repeat and secret non-disclosure
checks. Do not call a real S3 service or assert that the representative values
equal current role defaults.
Push the reviewed pipeline commit, import that exact public revision into the
collection through `git subtree pull --squash`, and extend only the
collection-level fixture inputs needed for native validation. The collection
suite should continue to prove artifact installation and one representative
assembled convergence rather than duplicate the detailed pipeline matrix.
## Rationale and Alternatives
Implementing storage behavior in Ansible would duplicate a mature native
application boundary. Narratio already owns credential resolution, AWS SDK
provider construction, immutable commits, verification, locks, restore,
caching, and cleanup. Passing declarative configuration through the generic
role is both smaller and more reliable.
Using the AWS SDK's ambient provider chain would avoid named secret files, but
the initial deployment has explicit Backblaze application credentials and the
suite already has a suitable managed typed-secret path. Keeping the two
credential-reference variables nullable preserves the ambient-provider
alternative: consumers can set both suite variables to `null` when their
deployment uses another provider.
Copying destinations into every publish rule would make the output layout more
visible locally, but it would duplicate paths already owned by Narratio's
built-in sources and the configured artifact definitions. Native destination
derivation keeps path coordination automatic.
Omitting explicit `required: true` values would avoid the v2.1.0 failure only
by relying on an unrelated defaulting path. Changing the generic role's YAML
format would not repair the underlying sequence-resolution mismatch. Narratio
v2.1.1 fixes the owning application boundary, allowing the suite to state its
requiredness policy directly without duplicating destinations.
Deleting spool audio after publication would minimize transient disk usage,
but no such retention policy has been selected, and local-audio sessions may
depend on that content. Leaving the field omitted preserves Narratio's default
while enabling the explicitly requested S3 audio cache.
Publishing all ten Notarius extraction lanes would create stable remote output
contracts that have not been requested. It is also unnecessary for the stated
future use: analyze-stage artifacts can consume `narratio.extraction.*`
directly. The immutable published run retains the processing result, while the
selected transcript and human-facing artifact outputs match the known
operational workflow.
## Acceptance Criteria
- The pipeline role declares and documents every suite variable shown in the
target state, with matching argument-spec entries and direct Narratio
dependency mappings.
- The pipeline installs Narratio v2.1.1, whose released configuration loader
supports explicit requiredness together with derived publish destinations.
- The two credential-reference variables accept paired `null` overrides so a
caller can deliberately select Narratio's ambient AWS SDK provider chain.
- The default effective Narratio configuration selects the specified
Backblaze-compatible S3 destination, typed credential names, S3 audio cache,
successful-publication workspace cleanup, run upload, and seven output
rules.
- The publish list relies on Narratio's native destination derivation and
retains `deranged_rumors` as optional while the other six outputs are
required.
- Spool-audio deletion remains unset by the pipeline role, and the testing
profile introduces no storage or publication override.
- `dnd_pipeline_secrets` remains a generic empty-by-default mapping; the role
documents all four expected operational entries without embedding any
credential value.
- No new production task, template, handler, fact, state file, wrapper, or
storage-validation command is introduced.
- The standalone Narratio role remains unchanged because its `v0.1.0` role
interface can install Narratio v2.1.1, renders the required native fields,
and preserves null omission.
- The existing pipeline integration scenario explicitly supplies
representative S3 and publish inputs, resolves synthetic values for all four
typed credentials, passes Narratio's native configuration validation, and
exposes no synthetic value in captured output.
- The immediate identical second pipeline application reports `changed=0`
and `failed=0`; syntax checking, production-profile lint, the complete
standalone integration suite, and `git diff --check` pass.
- The exact reviewed pipeline commit is pushed to public Gitea before the
collection imports it through the documented remote-only squashed subtree
workflow.
- The collection fixture supplies the added synthetic credential names, and
its existing build, isolated installation, FQCN resolution, native
validation, and clean-repeat suite passes without a duplicate S3 behavior
test.
- No real object-storage request, paid model request, application repository
change during the remaining implementation, asset change, new release tag,
or published artifact is required. The existing Narratio v2.1.1 release is a
prerequisite rather than an implementation deliverable.
- Pipeline documentation links operators to Narratio's canonical procedures
for S3 session audio, publish, restore, locks, status, and cleanup and no
longer describes storage and publishing as deferred.
- Documentation distinguishes accepted Notarius extraction sources from
published outputs and confirms that future analyze-stage artifacts may use
`narratio.extraction.<output_key>` inputs without publishing those lanes.
## Dependencies and Follow-up Work
Features 0009, 0011, 0012, 0013, and 0014 and the public Narratio v2.1.1 bugfix
release are prerequisites. In particular, Feature 0011 supplies the credential
directory and Feature 0014 supplies the human-operator access needed for the
eventual live deployment.
[Feature 0016](0016-deploy-dnd-pipeline-to-pipeline-dnd.md) follows this work.
It will put the four actual values in encrypted host inventory, pin the exact
reviewed suite revision in `rakestraw-ansible`, converge `pipeline-dnd`, and
exercise one real session through remote publication. Bucket lifecycle policy,
backup policy, credential rotation, additional publish outputs, automated
scheduling, and cleanup of the proof-of-concept deployment remain separate
future work.
A later artifact-development feature may add D&D-specific Narratio artifact
definitions whose Scriptorium input mappings consume selected
`narratio.extraction.*` sources. That feature should define each artifact's
purpose, inputs, prompt, output contract, and publication choice; it does not
require a storage-interface change.

View File

@@ -0,0 +1,149 @@
# Feature 0016: Prepare the D&D Deployment Playbook for `pipeline-dnd`
Status: done
## Summary
Write and commit the consumer playbook, necessary host variables, dependency
manifest, and concise usage documentation in `rakestraw-ansible`. This feature
ends with repository preparation. Deployment to a controller or target host
and execution of the pipeline are separate operator work.
## Scope
- `playbooks/pipeline/dnd.yml` targets the existing `pipeline-dnd` alias and
applies `rakestraw.dnd.pipeline`, using only hosts and roles.
- Host choices belong in `inventory/host_vars/pipeline-dnd/`: the WhisperX
endpoint, initial operator `eric`, default campaign `dilfs`, and credential
references. Unknown required values are explained in adjacent comments.
- Inherit the reviewed suite's storage, publication, caching, cleanup, and
application defaults. Retire obsolete legacy host variables.
- Root `requirements.yml` selects the reviewed public collection snapshot and
its role/native collection dependencies, preserving unrelated entries.
- Document local validation and eventual operator use. Commit the completed
repository changes without requiring remote access or real credentials.
## Non-goals
- Installing or updating anything on the operational controller or target.
- Connecting to `pipeline-dnd`, validating its platform or sudo access,
converging the host, checking runtime identities, or executing a real session.
- Obtaining API keys, choosing a Vault password, populating real credentials,
or selecting acceptance audio/session data.
- Changing application/role behavior, publishing a new suite release, adding
orchestration layers, or retiring the proof-of-concept role/playbook.
## Target End State
The committed playbook is:
```yaml
---
- hosts:
- pipeline-dnd
roles:
- rakestraw.dnd.pipeline
...
```
Existing connection variables remain in the host's `main.yml`. Its
`narratio.yml` contains the following public configuration and comments:
```yaml
dnd_pipeline_operator_users:
- eric
dnd_pipeline_whisperx_transcribe_url: >-
https://transcription.ai.rakestrawhome.com/transcribe
narratio_campaigns_default_campaign_id: dilfs
# Before deployment, define the four vault_dnd_* variables below in an
# Ansible Vault-encrypted host_vars/pipeline-dnd/vault.yml file.
# Values are not known here; leave these references unresolved until supplied.
# Do not put API keys or object-storage credentials in this plaintext file.
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 }}"
```
The references and comments are a complete deliverable for unknown secrets.
No encrypted file, placeholder key, or real credential is required for feature
completion. Future operator-supplied values should be Vault-encrypted in Git;
the suite's existing restricted runtime secrets files remain the delivery path.
The manifest pins the collection to
`2a53979069ff8d091172650729ae2135c1603163`, containing pipeline commit
`f48008aa38e1c50adde18aa455d12a8ad77023c2` with Narratio v2.1.2.
Its five standalone role dependencies
use their reviewed `v0.1.0` tags, with `ansible.posix` `2.2.0` and
`community.general` `13.3.0`. Suite Git dependencies use public Gitea URLs;
native collections come from Galaxy. Local sibling checkouts are not dependencies.
The runbook explains that the selected collection snapshot still reports
`0.1.0`, so eventual operator installation must explicitly refresh it from
the pinned commit if an older `0.1.0` is installed. This is an instruction
for future use, not an operation required by this feature.
## Repository Ownership
- `rakestraw-ansible`: consumer files, comments, dependency manifest, and runbook.
- Workspace: roadmap, staged plan, progress, and independent review record.
- Roles, collection, applications, and assets: read-only contract references.
## Constraints and Settled Decisions
The workspace [Ansible](../../ansible.md), [testing](../../testing.md), and
[planning](../../planning.md) policies apply. Feature 0015 has passed review
and supplies the required suite interface.
- Keep playbooks minimal and settings in inventory. Preserve `pipeline-dnd`
and its connection identity; do not rename it to `pipeline.dnd`.
- Preserve `dilfs` using the existing standalone Narratio variable. Remove
legacy `narratio_s3_*` and `narratio_default_campaign_id` host settings.
- Missing operational inputs are documented, not treated as implementation
blockers. No remote controller, SSH identity, Vault password, or session is
required for repository preparation.
- Local dependency installation and syntax/host-selection checks are permitted.
Existing passing evidence may be reused when relevant inputs are unchanged.
- `ansible-doc` rendering is not an acceptance gate. Missing role argument
descriptions are a separate documentation improvement.
## Simplest Viable Implementation
Retain the already-committed minimal playbook, manifest, and public inventory.
Add adjacent comments for unresolved credentials, align the runbook with the
repository-only scope, perform appropriate local checks, and commit. No new
Ansible task, runtime test harness, or deployment automation is needed.
## Acceptance Criteria
- The playbook targets only `pipeline-dnd` and applies only the collection role.
- Host inventory expresses the known choices above and documents unknown
credentials next to their references without real or fake secret values.
- The dependency manifest contains the reviewed public pins and preserves
unrelated dependencies. Public installation and local syntax/host-selection
evidence are available; no documentation-rendering check is required.
- The runbook distinguishes repository readiness from future deployment and
explains how the operator supplies missing values and eventually invokes it.
- Changes are committed in the owning repositories, with clean working trees
for the feature's changes. No controller deployment, target convergence,
clean-repeat run, or real pipeline execution is required or claimed.
- Historical role/playbook files remain available.
## Dependencies and Follow-up Work
Features 0013–0015 supply public dependencies, operator enrollment, and storage
policy. Consumer preparation was completed in `716a80e`, `12b2462`, and
`7f8353d`, and passed independent review with no remediation findings.
Public dependency installation, target-only host listing, syntax checking,
and whitespace validation passed. Subsequent consumer commit `7f4c90a`
updates the collection pin for the Narratio v2.1.2 bug fix; collection build
and syntax validation passed. These changes are committed and published.
The operator may later provision Vault values, install dependencies on their
controller, deploy to the host, and validate real processing/publication.
Those actions require a separate request and are not unfinished Feature 0016
acceptance requirements.

View File

@@ -0,0 +1,199 @@
# Feature 0017: Notarius Testing Overlay
Status: done
## Summary
Selecting Narratio's `testing` profile also selects a separately managed
Notarius `testing` configuration overlay. Operators can develop D&D assets
with economical extraction settings without modifying production configuration
or invoking Notarius separately.
## Problem or Opportunity
The suite's existing testing overlay changes Scriptorium selections but leaves
Notarius on its production configuration. Narratio v2.2.0 now provides the
explicit `pipeline.notarius.config_profile` interface requested by this consumer.
Notarius v0.7.1 retains the corresponding `--config-profile` option and updates
PromptKit and its provider catalogs. This feature adopts v0.7.1 as its baseline.
## Scope
- Expose the optional native selector in the standalone Narratio role.
- Update standalone Notarius and suite version defaults to v0.7.1, with
matching current-version documentation and collection distribution.
- Deploy a Notarius ConfigKit testing overlay through the suite role.
- Explicitly select that overlay from Narratio's existing testing overlay.
- Select `gpt-terra-latest` for production and `gpt-luna-latest` for testing,
while retaining inventory overrides for both choices.
- Document and validate the composed configuration, then distribute the
updated suite through the collection and refresh the consumer dependency pin.
## Non-goals
- Further upstream application changes or a Narratio-side LLM-profile override.
- Automatically propagating profile names between applications.
- Disabling Notarius, caching, publishing, or other pipeline stages for testing.
- New credentials, cache layouts, other production tuning, or deployment automation.
- Live controller/target deployment or paid model calls as completion gates.
## Target End State
### Standalone Narratio Interface
`narratio_notarius_config_profile` defaults to `null`. The role omits
`notarius.config_profile` when null and serializes explicitly supplied values,
including an empty string. Documentation and argument specifications expose
the field without duplicating or narrowing Narratio's selector semantics.
### Explicit Suite Composition
The suite leaves the base selector unset. Its existing Narratio
`profiles/testing.yml` includes:
```yaml
notarius:
config_profile: testing
```
The suite deploys `/usr/local/etc/notarius/profiles/testing.yml`. That file
overlays the selected suite pipeline's `llm_profile`, using
`dnd_pipeline_narratio_notarius_pipeline_id` as the pipeline key and a new
`dnd_pipeline_notarius_testing_llm_profile` variable as the value. It does not
copy the full pipeline definition. ConfigKit performs the ordinary merge.
The default suite pipeline currently inherits its LLM selection at pipeline
level. Caller-supplied binding-level selections retain Notarius's native
precedence; this feature does not rewrite arbitrary caller pipelines or promise
that a pipeline-level default overrides explicit binding choices.
### Production and Testing LLM Defaults
The suite's base `dnd-session` pipeline selects `llm_profile: gpt-terra-latest`
instead of `dnd-extraction`. Callers can continue overriding that choice through
the existing `dnd_pipeline_notarius_pipelines` mapping. The new
`dnd_pipeline_notarius_testing_llm_profile` defaults to `gpt-luna-latest`.
Both IDs are supplied by the OpenRouter catalog `v2.20260922.1` selected by
Notarius v0.7.1. Use those native catalog profiles directly; no operator profile
asset or profile-source setting is needed for these defaults. Retain the
existing `OPENROUTER_API_KEY` credential reference. These are deliberately
moving `latest` selections, not promises of immutable underlying model versions.
This production-model policy belongs to the suite, not the standalone role.
Notarius stays enabled and retains its configured caching, output contracts,
references, and production defaults outside this overlay. Existing Scriptorium
testing overrides remain intact. Credentials continue through the existing
typed reference and suite secrets interfaces; no credential values enter YAML.
Configuration files and directories use the suite's existing owner, group,
and mode variables. The selector and overlay add no new runtime identity or
filesystem-permission policy.
## Repository Ownership
- `ansible-role-narratio`: generic optional selector, documentation, and tests.
- `ansible-role-notarius`: v0.7.1 installation default and corresponding
documentation; existing profile-source settings remain sufficient.
- `ansible-role-dnd-pipeline`: testing policy, overlay assets, and composition.
- `ansible-collection-dnd`: imported pipeline snapshot and compatible dependency
manifest. Its current Narratio-role `v0.1.0` pin must advance to include the
new public variable; changing only the sibling role is insufficient.
- `rakestraw-ansible`: matching dependency pins and concise operator guidance.
- Workspace: roadmap, implementation plan, progress, and review.
- Narratio and Notarius applications: read-only authoritative contracts.
The standalone Notarius role already exposes profile-source settings and
does not need D&D-specific overlay policy.
## Constraints and Settled Decisions
Follow the [MVP roadmap](../mvp.md), [Ansible house style](../../ansible.md),
and [testing house style](../../testing.md). Narratio v2.2.0 is already selected
by the suite; Notarius v0.7.1 is the selected target. Consult these tags, not
only newer application checkouts.
### Notarius v0.7.1 Compatibility
The [upstream release notes](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.7.1/docs/releases/v0.7.1.md)
describe unchanged CLI, configuration, artifact, and subprocess contracts.
The application-owned `dnd-extraction` fallback retains its settings and no
configuration migration is required. Independently of that upstream behavior,
the user has selected `gpt-terra-latest` as this suite's new production default.
Profile selection must use the catalogs selected by v0.7.1 (PromptKit v0.10.0).
The removed `deepseek-3-2`, `deepseek-4-flash`, and `deepseek-4-pro` catalog IDs
must not be assumed available or silently replaced by similarly named profiles.
This is deployment guidance, not a request for an Ansible catalog validator.
Existing checkpoints with the previous profile-source identity are not reused;
source-keyed chunk plans and existing output artifacts are unaffected. Document
this upstream upgrade behavior without deleting caches or forcing Narratio
extraction automatically.
Each application owns its configuration. Narratio selects the downstream
overlay; Notarius resolves and validates it. Existing application behavior owns
extraction reuse when selections change and explicit-force handling for changes
behind a stable profile name. Do not add Ansible state tracking for either.
## Simplest Viable Implementation
Add one nullable role field and its conditional template output. Extend the
suite's existing directory/template management to deploy the Notarius overlay
and extend the existing Narratio testing template with the explicit selector.
Use native serialization and ordinary file/template modules. Select the two
existing catalog IDs rather than deploying duplicate profile definitions. No assembly facts,
preflight state probes, or generic overlay-management framework is required.
## Rationale and Alternatives
A downstream ConfigKit overlay can own model choices and later Notarius tuning
without expanding Narratio's configuration surface for each setting. Direct
LLM-profile forwarding would solve only the model-selection case. Automatic
profile propagation would couple unrelated profile names and is not selected.
## Acceptance Criteria
- The standalone role omits an unset selector and preserves explicitly supplied
representative values, including the empty-string base selector.
- Native configuration inspection shows Narratio testing selecting Notarius
testing, and Notarius testing selecting the requested LLM profile. Base
configuration retains its production selection.
- A representative inventory-supplied testing selection is supported. Tests
exercise behavior rather than asserting that today's default model stays fixed.
- Notarius's deployed-version validation accepts the composed pipeline and
selected profile. No paid inference is required.
- Existing integration coverage remains valid, and immediate repeated role
convergence reports no changes. Do not independently retest file-module
ownership, modes, or template-file existence.
- The built collection works with its declared public role dependencies; no
local sibling checkout is needed by consumers. Subtree imports follow the
documented public-Gitea workflow, and published tags remain immutable.
## Dependencies and Follow-up Work
The upstream selector shipped in Narratio v2.2.0; the downstream baseline is
now Notarius v0.7.1. Git history preserves the completed implementation plan.
Future testing-specific Notarius settings belong in its overlay but are not
implicitly included in this feature.
## Completion and Review Evidence
Completed and published in Narratio role `330afe7`, Notarius role `a82a83d`,
pipeline role `c56a942`, collection `ce5b838`, and consumer `0ced48c`.
Implementation reported passing full integration suites for both changed
application roles, the pipeline, and the collection, including clean repeated
convergence. Independent review found no code-quality issues, architecture gaps,
or unnecessarily strengthened requirements requiring remediation.
The review independently verified collection build and public dependency
installation, syntax and shell checks, native configuration validation,
consistent dependency pins, and exact subtree/source agreement. It reviewed
the recorded integration results without rerunning host-mutating suites.
Operational deployment and paid inference were neither required nor performed
as part of this feature review.
## Open Questions
None. The user selected `gpt-luna-latest` for testing and `gpt-terra-latest`
for production; both are available in the catalog selected by Notarius v0.7.1.

View File

@@ -0,0 +1,163 @@
# Feature 0018: Adopt Scriptorium v0.15.0 in the Standalone Role
Status: done
## Summary
Update the standalone Scriptorium role from v0.13.0 to v0.15.0 and expose its
new application-configuration settings using our existing nullable-variable
conventions. This is the first feature in the agreed
[application upgrade sequence](../application-upgrade-sequence.md).
## Problem or Opportunity
Although v0.15.0 primarily changes licensing and dependency versions, the
intervening v0.14.0 adopted ConfigKit and added application imports, overlays,
inspection, and transient retry controls. A version bump alone would leave
new configuration settings unavailable through the role's public interface.
The current role already emits `{}` for an unconfigured installation, omits
null optional fields, serializes mappings, and retains explicit falsey values.
Those practices remain compatible with the stricter upstream configuration
contract; no new production validation or migration mechanism is needed.
## Scope
- Adopt v0.15.0 as the standalone role's default source version.
- Expose ConfigKit imports and the application transient-retry setting.
- Confirm existing configuration variables and representative backend mappings
remain usable with the new application version.
- Update role documentation and focused offline integration coverage.
- Record completion and the role revision for later coordinated integration.
## Non-goals
- Changing pipeline, collection, consumer, or other application-role pins.
- D&D model choices, production/testing policy, or new provider credentials.
- Deploying prompt/profile/schema libraries or managing arbitrary overlay files.
- Selecting a runtime overlay for callers, managing a service, or adding HTTP
request/CLI-only controls such as execution reports and run deadlines to YAML.
- Upstream application changes, paid inference, or operational host deployment.
- Relicensing this Ansible role or copying upstream source/license material
into the role repository merely because the installed application changed.
## Target End State
### Installation and Existing Configuration
`scriptorium_version` defaults to `v0.15.0`. Retain the existing source checkout,
Go build, ownership, and permission behavior and the caller-selected version
interface. No build-toolchain change is required: the current Go 1.26 selection
satisfies the release's Go requirement.
Existing application fields keep their public variable names. Optional variables
remain null by default and are omitted; explicit supported zero/empty values
are serialized without truthiness checks. An installation with no application
settings still receives `{}`, not an empty file.
### New Public Variables
| Variable | Default | Rendered field |
| --- | --- | --- |
| `scriptorium_configkit_imports` | `null` | `configkit.imports` |
| `scriptorium_transient_retries` | `null` | `transient_retries` |
Imports are a native list of mapping entries, consistent with the other roles'
ConfigKit interfaces. Serialize the supplied list without reinterpreting path,
glob, or optional-entry semantics. Emit the parent section only when selected.
The caller owns referenced fragment and overlay files; ordinary inventory can
compose the list without a second raw-configuration interface.
Transient retries is an optional integer. Null means omit and inherit the
application/PromptKit default; zero explicitly disables additional transient
attempts. The standalone role does not freeze the upstream default or add a
retry budget of its own. Argument specifications and documentation describe
both variables consistently.
### Compatibility Guidance
Document the distinction between ConfigKit `overlays/` selected by
`--config-overlay` and PromptKit LLM profiles. Imports are configuration-root
relative, while application path values retain their process-working-directory
semantics. Link upstream for detailed validation and precedence rules.
Call out stricter YAML acceptance and changed retry behavior, plus the removal
of legacy DeepSeek catalog IDs, without installing compatibility aliases or
inventing role-side configuration guards. New fields should only be supplied
when selecting an application version that supports them.
Mention that Scriptorium v0.15.0's application grant is GPL-3.0-or-later and link
its tagged licensing notices. Do not conflate the application's grant with the
role's license or introduce legal approval as a deployment gate.
## Repository Ownership
- `ansible-role-scriptorium`: default version, variables, argument specification,
template, README, and repository-local tests.
- Workspace: feature roadmap, staged plan, progress, and review evidence.
- Scriptorium application: read-only tagged configuration/release contracts.
- Pipeline, collection, consumer, and asset repositories remain unchanged.
## Constraints and Settled Decisions
Follow the [Ansible house style](../../ansible.md),
[testing house style](../../testing.md), [MVP roadmap](../mvp.md), and
[upgrade sequence](../application-upgrade-sequence.md). Review the tagged
v0.15.0 contract rather than assuming later application changes apply.
The existing suite continues installing its current Scriptorium role/application
pins until final integration. Standalone adoption is not suite publication.
## Simplest Viable Implementation
Update the version default and extend the existing defaults, argument
specification, and single configuration template with the two optional fields.
Include both in the empty-document condition. Reuse the existing source/build
and file/template tasks unchanged. No additional runtime tasks are needed.
## Acceptance Criteria
- The default role installs v0.15.0 and native offline configuration validation
accepts the default and representative managed configurations.
- Representative non-null and falsey values remain correctly rendered; the new
retry field preserves explicit zero and is omitted when unset.
- A caller-supplied import is composed successfully by native configuration
inspection using a small externally supplied test fragment. An optional test
overlay can demonstrate native composition without adding role-owned overlay
management or retesting ConfigKit's complete precedence/error matrix.
- Existing offline profile/backend inspection remains useful and passes.
Application validation alone does not prove PromptKit source validity.
- Immediate repeated role application reports no changes. Tests assert supplied
configuration outcomes, not today's upstream/default version, catalog contents,
task arrangement, or file-module postconditions.
- Syntax/lint and repository integration checks pass without provider calls,
real secrets, or operational controller access.
- Suite and consumer pins remain unchanged, and completion identifies the role
commit available for the final integration feature.
## Dependencies and Follow-up Work
Git history preserves the completed staged plan.
Audita adoption is next. The eventual suite integration
feature owns propagation of the new role revision, deployment settings, and
coordinated upgrade guidance.
## Completion and Review Evidence
Completed in role commits `61dcafe`, `2fce529`, and `b174c8c`. Implementation
reported passing integration tests, including native configuration validation,
offline profile inspection, imports, explicit retry zero, and clean repeat
convergence. Independent review found no code-quality issues, implementation
gaps, or unnecessarily strengthened requirements requiring remediation.
Independent syntax, production-profile lint, shell syntax, whitespace, native
configuration validation, and focused template checks passed. The review used
recorded integration evidence without rerunning host-mutating suites. No new
production tasks or suite/collection/consumer pin changes were introduced.
No operational deployment is claimed.
## Upstream References
- [v0.15.0 configuration](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/docs/config.md)
- [v0.14.0 migration notes](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.14.0/docs/releases/v0.14.0.md)
- [v0.15.0 release and licensing notes](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/docs/releases/v0.15.0.md)

View File

@@ -0,0 +1,199 @@
# Feature 0019: Adopt Audita v2.0.1 in the Standalone Role
Status: done
## Summary
Replace the standalone Audita role's version-1 configuration interface with
Audita v2.0.1's native interface. Keep provider and D&D policy outside the
generic role. This is the second feature in the agreed
[application upgrade sequence](../application-upgrade-sequence.md).
## Problem or Opportunity
The role currently installs Audita v0.9.1 and renders version-1 configuration.
Audita v2 requires version-2 YAML, named backends, and selected PromptKit
profiles. Old per-role endpoint/model/credential/concurrency settings no longer
apply. A version-only update would produce an unusable deployment.
Unlike the previous minimal configuration, a valid v2 configuration requires
at least one backend and a proposal profile whose file exists. The generic role
must not invent a provider, endpoint, model, or credential to meet that contract.
The caller-input boundary is settled below.
## Scope
- Default to Audita v2.0.1 and configuration version 2.
- Replace retired public configuration variables with native v2 settings.
- Preserve still-supported domain controls and inventory composition.
- Document the breaking role-variable migration and caller prerequisites.
- Adapt offline integration tests to real v2 configuration/profile fixtures.
## Non-goals
- Updating pipeline, collection, or consumer application/dependency pins.
- Choosing D&D models, endpoints, credentials, concurrency, or retry budgets.
- Compatibility shims, automatic v1 conversion, or a dual-schema template.
- Live inference, operational deployment, report ingestion, service management,
or runtime configuration validation tasks.
- Imports: Audita deliberately disables ConfigKit imports. Do not add an import
variable merely because other applications expose one.
- Automatically provisioning secret values or selecting runtime overlays.
## Target End State
### Installation and Schema
`audita_version` defaults to `v2.0.1`; `audita_config_version` defaults to `2`.
Retain the existing source checkout, conditional Go build, dependency management,
configuration location, and owner/group/mode interfaces. Go 1.26 remains suitable.
The role renders v2 only; selecting an older application does not translate its
configuration. Operators needing v1 retain the previous role revision.
### Public Configuration Interface
Use these field-specific variables; optional settings default to null and are
omitted, allowing Audita to own defaults. Serialize native values and preserve
intentional zero, false, empty strings, and empty collections where supported.
| Role variable | Native field | Ownership |
| --- | --- | --- |
| `audita_profiles_dir` | `profiles_dir` | Optional caller profile location |
| `audita_backends` | `backends` | Caller-supplied native mapping |
| `audita_llm_proposal_profile` | `llm.proposal_profile` | Caller-selected required profile |
| `audita_llm_validation_profile` | `llm.validation_profile` | Optional; omission inherits proposal |
| `audita_llm_transient_retries` | `llm.transient_retries` | Optional native retry budget |
| `audita_llm_repair_attempts` | `llm.repair_attempts` | Optional native repair budget |
| `audita_llm_operation_timeout` | `llm.operation_timeout` | Optional duration string |
| `audita_validation_max_prompt_tokens` | `validation.max_prompt_tokens` | Optional batching control |
| `audita_reporting_enabled` | `reporting.enabled` | Optional report policy |
| `audita_reporting_stdout_dir` | `reporting.stdout_dir` | Optional report destination |
| `audita_diagnostics_debug` | `diagnostics.debug` | Optional debug policy |
Retain existing variables for modules, output schema, chunking, normalization,
thresholds, context description, and diagnostics work directory. Normalization
gap/duration fields now represent numeric seconds, not duration strings.
Argument specifications must accept the native integer/fractional values without
turning them into quoted strings in YAML. Do not add a duration-conversion layer.
Remove the old `audita_llm_{proposal,validation}_{base_url,model,api_key_env,timeout,max_retries}`,
`audita_concurrency_{total_llm,proposal_llm,validation_llm}`, and
`audita_diagnostics_retention` interfaces from defaults, templates, argument
specifications, and current examples. Document their replacements rather than
silently interpreting them under different semantics or adding deprecation probes.
The backend mapping carries endpoint, credential reference, concurrency, and
queue capacity using Audita's schema. Inventory can compose it with ordinary
Jinja expressions. Credential values stay outside the role; every surviving
backend reference must be available when Audita loads configuration, even when
that backend is not selected. Do not introduce separate per-role secret variables.
Null role variables mean omission, not literal YAML null. In particular, omit
an unset validation profile so Audita can inherit the proposal selection.
Backend mapping values retain native semantics, including a null credential.
### Profile and Overlay Ownership
Callers provide `audita_backends` and `audita_llm_proposal_profile`; neither has
a fabricated concrete default. Callers also deploy the selected profile files
before invoking Audita. `audita_profiles_dir` may be supplied or omitted to use
Audita's conventional sibling `profiles/` directory. Keep profile documents and
ConfigKit `overlays/` content caller-owned in this feature.
The later suite feature will own its D&D profile assets and coordinate their
deployment with Narratio's new external Audita configuration contract. The role
does not start processing or validate file availability during convergence.
## Repository Ownership
- `ansible-role-audita`: generic installation/configuration interface, migration
documentation, and local tests.
- Workspace: roadmap, active plan, progress, and review evidence.
- Audita application: read-only tagged schema, migration, and profile contracts.
- Other applications/roles, assets, pipeline, collection, and consumer: unchanged.
## Constraints and Settled Decisions
Follow the [Ansible house style](../../ansible.md),
[testing house style](../../testing.md), [MVP roadmap](../mvp.md), and
[upgrade sequence](../application-upgrade-sequence.md). The suite continues to
use its old compatible role/application set until final integration; Narratio v2
must not be accidentally paired with Audita v2 through a changed suite pin.
Old timeouts and retries do not map one-to-one to profile per-attempt timeouts,
logical-operation deadlines, transport retries, and structural repair. Expose
native controls without choosing replacement tuning for the D&D suite here.
## Simplest Viable Implementation
Update the version/schema defaults and replace the single configuration template's
retired sections with native v2 sections. Align argument specifications and the
README. Keep ordinary file/template/source/build tasks. Use the existing test
harness with caller-owned local backend/profile fixtures; add no state assembly,
profile resolver, migration command, or production probe.
## Acceptance Criteria
- The role installs v2.0.1 and renders native v2 configuration from supplied
backend/profile choices and optional settings.
- Native offline validation and effective-settings/profile inspection accept
representative configuration with an externally supplied profile and local
fixture endpoint; no provider request is needed.
- Tests cover supplied mapping composition, omission/inherited validation
selection, representative numeric seconds, and meaningful zero/false values.
Avoid a comprehensive schema matrix or assertions of current upstream defaults.
- Existing useful build and clean-repeat coverage remains. Immediate repeated
role convergence reports no changes; do not test module postconditions.
- Documentation explains required caller inputs and the breaking variable/schema
migration, linking Audita for full field and report semantics.
- No suite, collection, or consumer pins change. Completion records the reviewed
standalone role revision for the final integration feature.
## Rationale and Alternatives
Native backend mappings and named profiles preserve Audita's ownership instead
of reproducing per-role endpoint/model settings in Ansible. A dual-schema role
would add maintenance and ambiguity without a selected requirement; retaining
the previous role revision is the simpler boundary for old deployments.
## Dependencies and Follow-up Work
Git history preserves the completed staged plan. Notarius adoption is next.
D&D backend/profile assets,
tuning migration, testing overlays, credential lists, and coordinated deployment
belong to the later integration feature.
## Settled Caller-Input Decision
The user approved required `audita_backends` and `audita_llm_proposal_profile`
inputs through the ordinary role argument interface, with caller-owned profile
files. Do not give these variables null or fabricated defaults. A no-input role
invocation is no longer valid; examples and tests supply explicit choices.
Role-managed profile definitions are not part of this feature.
## Open Questions
None.
## Completion and Review Evidence
Completed in role commits `6137ff2`, `52f67fe`, and `c3dd59f`. Implementation
reported passing integration tests with native v2 validation, offline profile
inspection, mapping composition, omission, numeric seconds, falsey values,
build/recovery coverage, and clean repeated convergence.
Independent review found no code-quality issues, implementation gaps, or
unnecessarily strengthened requirements needing remediation. Independent
Ansible syntax, production-profile lint, shell syntax, whitespace, and focused
template checks passed. The review used recorded native/integration results
without rerunning the host-mutating suite.
No production tasks were added. Profile files remain caller-owned, and suite,
collection, and consumer pins remain unchanged. No operational deployment or
paid inference was performed as part of this review.
## Upstream References
- [v2.0.1 configuration](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.1/docs/config.md)
- [v2 migration guide](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.1/docs/migrations/v2.md)
- [v2.0.1 release](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.1/docs/releases/v2.0.1.md)

View File

@@ -0,0 +1,173 @@
# Feature 0020: Adopt Notarius v0.8.1 in the Standalone Role
Status: done
## Summary
Update the standalone Notarius role from v0.7.1 to v0.8.1, expose the new
PromptKit transient-retry setting, and document the ConfigKit overlay rename.
This is the third feature in the agreed
[application upgrade sequence](../application-upgrade-sequence.md).
## Problem or Opportunity
Notarius v0.8.0 renamed configuration selection to `--config-overlay` and
`overlays/<name>.yml`, removing the previous flag and lookup directory. It also
introduced configurable provider transport retries. v0.8.1 updates ConfigKit
and PromptKit to v0.4.2 and v0.11.2 without further intentional configuration or
subprocess-contract changes.
The standalone role currently renders schema version 5, supports native imports
and caller-supplied pipelines, and leaves profile assets externally managed.
Those boundaries remain appropriate. The suite, however, still uses the old
downstream selector; its application and dependency pins must not advance yet.
## Scope
- Default the standalone role to Notarius v0.8.1.
- Expose `promptkit.transient_retries` through one nullable role variable.
- Verify existing imports, pipeline composition, profile-source settings, and
cache configuration remain compatible with the target release.
- Update standalone compatibility guidance and focused offline tests.
- Record the reviewed role revision for later coordinated suite integration.
## Non-goals
- Updating suite, collection, consumer, or other application-role pins.
- Migrating suite-owned testing files or Narratio's downstream selector.
- Deploying arbitrary overlay or LLM-profile assets in the generic role.
- Choosing D&D model, retry, timeout, or credential policy.
- Automatic renames, compatibility aliases, cache deletion, forced extraction,
or production validation tasks.
- Upstream application changes, live inference, or operational deployment.
## Target End State
### Installation and Configuration
`notarius_version` defaults to `v0.8.1`. Configuration remains schema version 5.
Preserve existing build, dependency, path, and owner/group/mode interfaces.
The existing Go selection remains unchanged.
Add `notarius_promptkit_transient_retries: null`, documented and declared as an
optional integer in argument specifications. When non-null, serialize it as
`promptkit.transient_retries`. Include it in the parent-section condition so a
retry-only configuration renders correctly. Null means omit the field; zero
disables additional transient attempts. Do not copy PromptKit's default into
role defaults, add a second retry mechanism, or reinterpret existing module
and validator retry settings.
Keep all existing supported native configuration variables. Preserve caller
mapping/list composition and omission of unset optional settings. The role does
not resolve, inspect, or rewrite caller-owned profile or overlay files.
### Overlay Migration Guidance
Document `--config-overlay` and the conventional `overlays/` directory for
operators invoking the new application. The old `--config-profile` and ConfigKit
`profiles/` lookup no longer work. This does not rename PromptKit LLM-profile
sources: `notarius_promptkit_profile_dir`, `notarius_promptkit_profile_file`,
pipeline `llm_profile`, and `--llm-profile` retain their separate meanings.
Caller-owned configuration overlay files must be migrated by their owner. In
this workspace the D&D suite owns its testing overlay, so that migration belongs
to final integration together with Narratio's new selector. Do not add generic
file-moving tasks or broaden this feature to fix the old suite in place.
### Retry and Checkpoint Compatibility
Explain that transport retries are additional attempts per generation and are
separate from pipeline/validator retries. Omission inherits upstream behavior;
operators may explicitly select zero. Later suite planning will review combined
retry and timeout budgets rather than copying old values mechanically.
Document v0.8.1's changed profile-source checkpoint identity: old matching
checkpoint identities are not reused, while source-keyed chunk plans and
published output are unaffected. Leave cache lifecycle with Notarius and do not
delete data or force Narratio stages as part of installing the role.
## Repository Ownership
- `ansible-role-notarius`: version default, optional retry field, argument
specification, template, documentation, and repository-local tests.
- Workspace: feature roadmap, staged plan, progress, and independent review.
- Notarius application: read-only tagged configuration/release contracts.
- Pipeline, collection, consumer, other roles, and assets remain unchanged.
## Constraints and Settled Decisions
Follow the [Ansible house style](../../ansible.md),
[testing house style](../../testing.md), [MVP roadmap](../mvp.md), and
[upgrade sequence](../application-upgrade-sequence.md). Use v0.8.1's contract,
including the intervening v0.8.0 migration notes, not assumptions from a newer
application checkout.
Retain meaningful tests that explicitly install v0.7.0 to prove caller-selected
version behavior. Leave the new retry field unset in those older-version cases;
do not change them merely because the role default advances.
## Simplest Viable Implementation
Update the application version and add one optional variable, argument-spec
entry, and conditional template field. Extend the existing integration fixture
with explicit retry zero and native configuration inspection. No new production
tasks, state probes, compatibility framework, or role-managed assets are needed.
## Rationale and Alternatives
The role manages persistent configuration; application invocation owns overlay
selection. Adding an overlay-selection variable or file-migration tasks here
would confuse those responsibilities. Documenting the breaking invocation
change and coordinating it later preserves independently usable roles and the
existing suite compatibility set.
## Acceptance Criteria
- The default role installs v0.8.1, and native offline validation accepts the
baseline and representative managed configurations.
- Null retry selection is omitted; explicitly supplied zero is rendered and
visible through native effective-configuration inspection. A retry-only
configuration produces its enclosing PromptKit section.
- Existing useful coverage for native import/pipeline composition, profile
configuration, cache settings, selected application version, and supplied Go
executable remains valid. Do not add a comprehensive upstream schema matrix.
- Immediate repeat convergence reports no changes. Tests assert supplied values
and role outcomes, not today's version/catalog defaults or module postconditions.
- Documentation accurately distinguishes configuration overlays from LLM
profiles and describes retry/checkpoint upgrade consequences.
- Syntax/lint and repository integration checks pass without live provider
calls or operational-host access.
- Suite, collection, and consumer pins stay unchanged; the reviewed standalone
revision is recorded for final integration.
## Dependencies and Follow-up Work
Implementation and independent review are complete. Git history preserves the
completed staged plan. Narratio v3 standalone adoption is next. Final integration
owns the coordinated overlay/credential/configuration migration and public suite
dependency updates. No open product decision is required for this narrow scope.
## Implementation Evidence
- Standalone role commits: `b1b922c` (v0.8.1 default and optional retry
interface), `380b6a3` (integration coverage), and `6aef48b` (upgrade
guidance). No production tasks or suite dependencies changed.
- Syntax check and production-profile lint passed. `bash -n` and the local
integration harness passed with native offline configuration validation,
rendered/effective retry checks, older-version and supplied-Go behavior,
import and pipeline composition, and clean immediate repeats. Role and
workspace whitespace checks passed.
- Independent review of all three role commits found no required remediation
or unjustified strengthening of requirements. Syntax, production-profile
lint, shell syntax, whitespace checks, and installed v0.8.1 native
configuration validation passed again during review. The review used the
recorded successful integration run rather than rerunning its host-mutating
scenarios. No remediation document was changed.
- Reviewed standalone revision: `6aef48b`. Narratio adoption and coordinated
suite migration remain separate follow-up work; suite pins are unchanged.
## Upstream References
- [v0.8.1 configuration](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.8.1/docs/config.md)
- [v0.8.0 migration notes](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.8.0/docs/releases/v0.8.0.md)
- [v0.8.1 release notes](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.8.1/docs/releases/v0.8.1.md)

View File

@@ -0,0 +1,234 @@
# Feature 0021: Adopt Narratio v3.0.0 in the Standalone Role
Status: done
## Summary
Update the standalone Narratio role from v2.2.0 to v3.0.0 and align its
configuration interface with the new Audita and Notarius contracts. This is
the fourth feature in the agreed
[application upgrade sequence](../application-upgrade-sequence.md). Suite
integration remains a separate, subsequent feature.
## Problem or Opportunity
Narratio v3 replaces configuration-profile terminology with overlays, replaces
singular downstream credential references with lists, and delegates Audita v2
configuration to Audita. The existing role still exposes retired fields that
v3 rejects. Advancing only the executable would therefore leave callers and
the representative configuration fixture with an incompatible interface.
## Scope
- Default the standalone role to Narratio v3.0.0.
- Align defaults, argument specifications, template, examples, and tests with
the changed downstream configuration fields.
- Document operator migration, ownership boundaries, and native compatibility
consequences without automating session or asset migration.
- Record the independently reviewed role revision for final suite integration.
## Non-goals
- Updating pipeline, collection, consumer, or other application-role pins.
- Deploying downstream applications, changing D&D defaults, or migrating
suite-owned testing overlays and credentials.
- Creating arbitrary overlay assets or selecting Narratio's runtime overlay
through an installer variable.
- Compatibility aliases, dual-version template branches, automatic migration
of existing manifests, cache deletion, or forced stage reruns.
- New production validation, credential discovery, runtime version gates,
forwarding/redaction machinery, or upstream application changes.
- Live providers, operational deployment, or publication.
## Target End State
### Standalone Installation
`narratio_version` defaults to `v3.0.0`. Preserve source-build behavior, Go
selection, service account, filesystem paths, owner/group/mode interfaces, and
the required caller-supplied WhisperX URL. Configuration continues to use the
existing root document shape and one ordinary template task. Unchanged native
fields and caller composition remain supported.
### Audita Interface
Add the following optional variables with null defaults. Field paths below
refer to the root configuration document's `audita` section; upstream prose
also calls this `pipeline.audita`.
| Role variable | Native field | Argument type |
| --- | --- | --- |
| `narratio_audita_credentials` | `audita.credentials` | list of strings |
| `narratio_audita_overlay` | `audita.overlay` | string |
| `narratio_audita_proposal_profile` | `audita.proposal_profile` | string |
| `narratio_audita_validation_profile` | `audita.validation_profile` | string |
Remove these retired role variables and their rendered fields:
- `narratio_audita_llm_api_key`
- `narratio_audita_base_url`
- `narratio_audita_model`
- `narratio_audita_total_llm_concurrency`
- `narratio_audita_proposal_llm_concurrency`
- `narratio_audita_validation_model`
- `narratio_audita_validation_llm_concurrency`
- `narratio_audita_work_dir_retention`
- `narratio_audita_report`
Retain binary, timeout, modules, transcript description, config path, and output
schema variables. Null modules are omitted; explicit `[]` means no correction
modules. Audita owns backend definitions, model/profile contents, concurrency,
reporting, and debug policy. Document migration to Audita's own configuration
without trying to infer replacements for those policies.
### Notarius Interface
Replace `narratio_notarius_config_profile` with
`narratio_notarius_config_overlay`, an optional nullable string rendered as
`notarius.config_overlay`. Preserve supplied empty strings, `default`, and
named selectors exactly; null omits the selector. Selection is independent of
Narratio's own overlay and is not a PromptKit LLM-profile selection.
Replace `narratio_notarius_llm_api_key` with
`narratio_notarius_credentials`, an optional nullable list of strings rendered
as `notarius.credentials`. Preserve other Notarius configuration interfaces,
including cache controls, references, and output mappings.
### Rendering and Credential Ownership
Use `is not none`, appropriate serialization, and parent-section conditions
covering the new variables. Null omits a field; empty lists and strings remain
explicit. Do not copy native defaults into optional role defaults.
Credential lists contain environment-variable/secret-reference **names**, not
secret values. Narratio resolves and forwards them under their exact names.
The role neither resolves credentials nor infers them from downstream files.
Null omits the field and `[]` emits an explicit empty list; Narratio overlays
replace lists rather than append to them. Operators must list every backend
credential needed by the selected Audita configuration, including configured
but unselected backends. Notarius likewise requires names matching its selected
provider configuration. Resolution occurs at pipeline loading, even when a
downstream stage will not execute.
Removing retired variables is a documented breaking role-interface migration.
Do not add alias precedence, version-dependent rendering, or special guards
for old inventory. Users retaining old deployments retain their old role pin.
### Operator Upgrade Guidance
- Replace Narratio `--profile` with `--overlay` and selected `profiles/` files
with `overlays/`. Explicit imports from a directory named `profiles` remain
valid; this is not a blanket filesystem rename or an LLM-profile rename.
- Migrate downstream Notarius selection to `config_overlay` and its selected
files to `overlays/`. Named selection needs a supporting Notarius executable;
v0.8.1 is the tested baseline, not a new unconditional role version gate.
- Audita v2 must be configured independently before running polish. Narratio
does not generate its config or infer downstream overlay/profile selectors.
- Link the tagged manifest migration procedure: back up old manifests and
migrate `effective_config.selected_profile` to `selected_overlay` while
preserving progress/checkpoint state. Do not rewrite immutable remote
snapshots or infer that every stage must rerun.
- Note the native extraction-resume consequence for renamed named Notarius
selectors: the next applicable run regenerates extraction with normal
dependent invalidation. Omitted/base selections do not gain invalidation
solely from this rename. The role does not implement this behavior.
## Repository Ownership
- `ansible-role-narratio`: standalone interface, template, documentation, and
repository-local tests.
- Workspace: roadmap, later staged plan, status, and independent review.
- `../narratio`: read-only authoritative v3.0.0 contracts.
- Pipeline, collection, consumer, assets, and other roles remain unchanged.
## Constraints and Settled Decisions
Follow the [Ansible house style](../../ansible.md),
[testing house style](../../testing.md), [MVP roadmap](../mvp.md), and
[upgrade sequence](../application-upgrade-sequence.md). Use tagged v3.0.0
contracts rather than assuming a newer checkout has the same interface.
Keep meaningful explicit v2.1.0 version-selection and supplied-Go recovery
tests where their baseline inputs remain compatible. Do not turn configurable
version selection into a promise that new configuration fields work on old
applications; new fields stay unset in those cases.
## Simplest Viable Implementation
Change the version default and the affected defaults, argument-spec entries,
and conditional template fields. Adapt existing representative fixtures and
native validation to the new public interface. No additional production tasks,
state probes, file migration, or configuration assembly mechanism is needed.
## Rationale and Alternatives
Expose the native v3 interface directly instead of retaining aliases or
translating legacy Audita tuning into guessed backend/profile definitions.
This preserves application ownership and avoids a compatibility framework in
the generic installer. Coordinated suite migration can then make explicit D&D
policy choices against already-reviewed standalone roles.
## Acceptance Criteria
- The default role installs Narratio v3.0.0; native offline validation accepts
baseline and representative rendered configuration.
- Added and renamed fields agree across defaults, argument specifications,
template, examples, and documentation. Retired native fields are not emitted.
- Focused behavioral cases demonstrate null omission, supplied credential-name
lists, explicit empty lists, named/empty downstream selectors, and existing
meaningful falsey and artifact-composition behavior. Keep this representative,
not a matrix of every native rule or a snapshot of today's defaults.
- Native validation uses synthetic credential values supplied only to the test
process as needed; managed configuration contains names, not values. No live
provider calls or reimplementation of upstream forwarding/redaction tests is
required. Preserve existing useful log checks without expanding their scope.
- Immediate identical role application reports no changes. Selected-version
and supplied-Go/missing-binary outcomes remain covered.
- Syntax/lint and local repository integration checks pass. No operational
controller, target deployment, downstream pipeline execution, or real keys
are prerequisites for standalone-role acceptance.
- Documentation explains breaking variable changes and links upstream upgrade
procedures. No production validation or automatic migration has been added.
- Suite, collection, and consumer pins remain unchanged. Independent review
records the standalone revision for coordinated integration.
## Dependencies and Follow-up Work
Standalone adoption and independent review are complete for all four upgraded
applications. Git history preserves the completed staged plan. The next,
coordinated integration feature owns D&D
configuration, credentials, overlay assets, coordinated dependency pins,
collection assembly, and consumer migration guidance. It must deliberately
review retry/timeout budgets rather than copying retired tuning mechanically.
## Open Questions
None identified for this standalone scope.
## Implementation Evidence
- Standalone role commits: `a28f22c` (v3 interface and migrated fixtures),
`45f6836` (selector and credential-list coverage), and `3c0700b` (upgrade
guidance). Production tasks, suite dependencies, collection, and consumer
remain unchanged.
- `bash -n` and the local integration harness passed. The harness includes
syntax check and production-profile lint and exercised native offline
baseline, named, and explicit-empty validation, selected v2.1.0 behavior,
supplied-Go recovery, synthetic credential loading, and clean immediate
repeats. Role and workspace whitespace checks passed.
- Independent review on 2026-09-29 found no required remediation or unjustified
strengthening of requirements. Syntax checks, production-profile lint, shell
syntax, whitespace checks, and native v3.0.0 configuration validation passed
again during review. The review used recorded successful integration runs
rather than rerunning their host-mutating scenarios. No remediation document
was changed.
- Reviewed standalone revision: `3c0700b`. Coordinated suite migration remains
separate follow-up work; suite, collection, and consumer pins are unchanged.
## Upstream References
- [Narratio v3.0.0 release](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/releases/v3.0.0.md)
- [Configuration](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/config.md)
- [Audita integration](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/integrations/audita.md)
- [Notarius integration](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/integrations/notarius.md)
- [Operator migration procedures](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/operations.md)

View File

@@ -0,0 +1,300 @@
# Feature 0022: Integrate the Reviewed Application Upgrades
Status: done
## Summary
Bring the four reviewed standalone upgrades into the D&D pipeline role,
collection, and deployment consumer as one compatible configuration set.
This completes the agreed
[application upgrade sequence](../application-upgrade-sequence.md).
## Problem or Opportunity
The standalone roles now support the new releases, but the suite intentionally
retains its previous pins and configuration. Audita still receives v1 settings;
Narratio and Notarius testing selection still uses retired profile terminology.
Updating executable versions alone would break the deployed configuration.
## Scope
- Adopt the reviewed application/role versions together.
- Provide Audita v2 backend configuration and suite-owned PromptKit profiles.
- Migrate Narratio credential forwarding and Narratio/Notarius testing overlays.
- Preserve D&D processing, artifact composition, storage/publishing, shared
filesystem, and operator-access behavior.
- Update the collection snapshot, public dependency manifests, consumer pins,
operator guidance, and focused offline integration coverage.
## Non-goals
- Deploying to the operational controller or `pipeline-dnd` host, running real
transcripts, or calling inference, WhisperX, or object-storage services.
- New models, prompts, artifact families, extraction lanes, or processing policy
beyond migration choices expressly approved here.
- Automatic manifest conversion, cache deletion, forced stage reruns, broad
directory cleanup, compatibility aliases, or runtime version/integrity probes.
- Changing generic standalone-role ownership or adding production validation.
- A newly tagged collection release or replacement of published 0.1.0 assets.
This feature updates the public development compatibility set; formal release
packaging remains a separate decision.
## Target End State
### Coordinated Versions and Distribution
| Application | Suite version | Reviewed standalone role revision |
| --- | --- | --- |
| Scriptorium | v0.15.0 | `b174c8c` |
| Audita | v2.0.1 | `c3dd59f` |
| Notarius | v0.8.1 | `6aef48b` |
| Narratio | v3.0.0 | `3c0700b` |
| Seriatim | v1.5.0, unchanged | existing v0.1.0 role pin |
Dependency manifests use full immutable revisions resolved from these reviewed
commits. The pipeline role remains authoritative; the collection imports its
completed revision through the established public Gitea subtree workflow, never
by editing `roles/pipeline` directly. The collection continues bundling the
pipeline role and declaring standalone role dependencies separately.
Relevant reviewed commits must be published to their existing public origins
before downstream manifests/subtree imports depend on them. Publication of the
required Git commits is part of the eventual implementation workflow, not this
roadmap-writing pass. Do not rewrite tags or publish unrelated changes.
The consumer keeps its minimal playbook and host-vars organization. Its role
and collection pins select the same compatibility set. No controller install
or remote playbook execution is an acceptance gate.
### Audita Backend and Profile Ownership
The pipeline role supplies `audita_backends`, profile selection, and schema-2
settings to the standalone Audita role. The pipeline owns the missing profile
assets under `/usr/local/etc/audita/profiles/`, using its runtime owner/group and
configuration modes. This directory contains PromptKit LLM profiles, not
ConfigKit overlays; it must not be renamed to `overlays`.
Approved suite interface:
- `dnd_pipeline_audita_backends`: native backend map, defaulting to one backend
named `dnd`, endpoint `https://inference.ai.rakestrawhome.com/v1`, credential
reference `AUDITA_LLM_API_KEY`, and shared concurrency `4`. Omit queue capacity
to inherit the native default.
- `dnd_pipeline_audita_profiles`: a native profile mapping keyed by file/profile
ID, with complete `dnd-proposal` and `dnd-validation` entries. Each selects
backend `dnd`, model `google/gemma-4-31b-it`, and per-attempt
`timeout_seconds: 900`. Other model controls inherit native behavior.
- `dnd_pipeline_audita_llm_proposal_profile` and
`dnd_pipeline_audita_llm_validation_profile` select those respective IDs.
Render each supplied profile as one safely serialized native mapping with its
matching ID. Document profile-map keys as filename-safe IDs. Do not introduce
per-provider templates, profile merging, or discovery of external assets.
Callers can compose native maps in inventory and replace the supplied maps.
As with existing managed secrets, removing a map entry does not imply pruning
arbitrary files; only selected profiles participate in normal execution.
Preserve the ordered module sequence, `audita-v1` output, chunking values,
thresholds, context description, and normalization limits. Convert normalization
duration defaults from `3s`, `3s`, and `240s` to numeric `3.0`, `3.0`, and
`240.0` seconds. Preserve meaningful setting names where native semantics are
unchanged; update argument types accordingly.
Remove retired per-role endpoint/model/credential/concurrency/retry variables
in favor of the native backend/profile interface. Document their replacements;
do not infer a conversion from arbitrary old inventory. Remove diagnostics
retention; leave debug disabled through native defaults. Retain the existing
diagnostics work-directory choice where still supported. Reporting follows
Audita's native configuration; Narratio consumes its ordinary output contract.
Production and testing continue using the same Audita endpoint and model.
No separate Audita testing overlay is needed for an identical configuration.
### Credential Lists and Overlay Selection
Replace the suite's singular Narratio Notarius credential variable with
`dnd_pipeline_narratio_notarius_credentials`, default `[OPENROUTER_API_KEY]`.
Add `dnd_pipeline_narratio_audita_credentials`, default `[AUDITA_LLM_API_KEY]`.
Pass both through the reviewed Narratio role's native list variables. These
lists contain names, never values, and can be replaced with `[]`. Operators
overriding Audita backends must explicitly list all referenced credentials;
the suite does not inspect configurations to discover names.
Preserve `dnd_pipeline_secrets`, existing secret names, Vault references,
protected secret directory/files, and ordinary world-readable nonsecret
configuration. No credential rotation, secret relocation, or forwarding logic
is required in Ansible.
Deploy the suite-owned testing files at:
- `/usr/local/etc/narratio/overlays/testing.yml`
- `/usr/local/etc/notarius/overlays/testing.yml`
Narratio testing sets `notarius.config_overlay: testing`; production omits the
selector. Notarius remains enabled in both modes. Its production pipeline
continues selecting `gpt-terra-latest`, testing selects `gpt-luna-latest`, and
the existing caller-overridable pipeline map/ID behavior remains intact.
Scriptorium testing still selects `gemini-flash-latest`; production continues
using the prompt assets' selections. Retain separate artifact/family fragments.
Use Narratio `--overlay testing` and Notarius `--config-overlay testing` in
tests and operator examples. Deploy the new files declaratively; leave ignored
legacy `profiles/testing.yml` files alone and document that they are obsolete.
Do not delete `profiles/` directories or conflate them with PromptKit profiles.
### Runtime Paths and Existing Suite Behavior
Keep Narratio's explicit downstream binaries/config paths, output handoffs,
Notarius `/var/cache/notarius` roots and resume behavior, shared writable
directories/ACLs, service user, operator enrollment, and S3/publishing choices.
Audita profiles are configuration assets, not shared output directories.
No new runtime storage architecture is required.
### Retry and Timeout Policy
Retain the previously selected per-attempt Audita profile timeouts of 900
seconds while inheriting the new applications' retry,
repair, and whole-operation defaults. Expose nullable suite pass-throughs for
`audita_llm_transient_retries`, `audita_llm_repair_attempts`,
`audita_llm_operation_timeout`, `notarius_promptkit_transient_retries`, and
`scriptorium_transient_retries`, prefixed with `dnd_pipeline_` in the public
suite interface. Null means omit; explicit zero is preserved where valid.
Do not mechanically translate old `max_retries: 3` into both transport retries
and structural repairs. Preserve explicitly authored Notarius module retries;
they are a separate behavior. Keep Narratio stage timeouts unchanged. Explain
the nested budgets and the changed semantics, not a guarantee of identical
provider cost or timing.
## Repository Ownership
- `ansible-role-dnd-pipeline`: suite defaults, argument specs, dependency wiring,
Audita profile assets, testing overlays, documentation, and integration tests.
- `ansible-collection-dnd`: imported pipeline snapshot, dependency manifest,
collection tests, and compatibility guidance.
- `rakestraw-ansible`: matching dependency pins and deployment guidance; adjust
host variables only where required. Preserve Vault content and unrelated
inventory. Keep the hosts-and-roles playbook minimal.
- Standalone role repositories: reviewed commits are reused/published, not
redesigned. Application and campaign/prompt repositories are read-only
contracts/assets unless a concrete incompatibility is raised for discussion.
- Workspace: roadmap, later staged plan, decisions, progress, and review.
## Constraints and Settled Decisions
Follow the [Ansible](../../ansible.md), [testing](../../testing.md), and
[planning](../../planning.md) policies, [MVP roadmap](../mvp.md), and
[upgrade sequence](../application-upgrade-sequence.md). New D&D policy remains
in the pipeline role; optional generic application defaults remain null.
## Simplest Viable Implementation
Update dependency variables/pins and existing templates, add an ordinary
Audita profile directory task and one looped template deployment, and change
testing destinations to `overlays/`. Reuse existing declarative convergence,
secret delivery, and collection assembly. No production validation, state
fingerprints, migration framework, or generated credential inference is needed.
## Acceptance Criteria
- Pipeline and collection installations produce a compatible set of the four
upgraded applications while Seriatim remains unchanged.
- Native offline inspection/validation accepts Audita settings and selected
profiles, Notarius base/testing configurations, Scriptorium configuration,
and Narratio base/testing composition with synthetic credential inputs.
Direct Audita validation receives credential environment variables explicitly:
it does not bootstrap Narratio's secrets directory on its own.
- Focused cases prove caller-supplied backend/profile configuration and
credential lists, testing selection, and existing important composition and
path handoffs. Assert supplied values, not fixed copies of today's defaults.
- Immediate repeated convergence is clean. Existing meaningful shared-user,
cache, artifact-composition, and installed-collection behavior remains covered
without expanding into upstream module/runtime regression matrices.
- Collection build/install and consumer syntax checks use the established
public dependency manifests. No sibling application/role checkout is needed
by an external consumer. Required referenced commits exist on public Gitea.
- Consumer inventory retains comments/Vault references for unknown secrets;
no actual keys or operational deployments are required for completion.
- Guidance covers breaking inventory fields, new CLI selectors, obsolete
testing-file locations, and upstream manifest migration. Back up and migrate
local provenance without deleting progress or editing immutable snapshots;
document normal named-selector invalidation rather than forcing reruns.
## Open Questions
None. The user approved deferring to application defaults wherever possible,
with nullable inventory overrides, and confirmed retaining the existing
900-second Audita per-attempt policy. Do not freeze native retry, repair, or
operation-deadline defaults in suite variables. Operators should note that an
attempt may consume the entire logical-operation budget; these are separate
controls, not additive timeout guarantees.
## Dependencies and Follow-up Work
Features 0018–0021 provide the reviewed standalone revisions. Implementation,
independent review, and remediation are complete. Git history preserves the
completed staged implementation plan. Actual deployment,
session migration, live processing, and a formal tagged release are separate
operator actions, not completion gates for this feature.
## Implementation Evidence and Review Handoff
On 2026-09-29, the four reviewed standalone role revisions were published to
their existing public Gitea `origin/main` branches and verified after fetch:
Scriptorium `b174c8c2990bb79f8149d8f288c5e06ccb42bd73`, Audita
`c3dd59f5ac9b942306ffe540ae9e71d493998137`, Notarius
`6aef48b7e12e3651971444b8c224d96ff1879e6c`, and Narratio
`3c0700b5323293d44e3b1e67a50074d82d7a3bff`.
The pipeline role at public revision
`ea8b09e190419586ede6df3815d1ea999a0f4391` passed `bash -n`, its full
`tests/integration` harness twice (configuration migration and representative
override coverage), and `git diff --check`. The collection imported that exact
public revision by subtree; public collection revision
`3d77eb382bcb4c1742015d3c32e23630bb8c73bf` passed `bash -n`, its full
artifact-based `tests/integration`, and `git diff --check`. Both harnesses used
synthetic credentials and offline native application validation, with clean
repeats. The consumer's local commit
`f694dad9426ee21138b175e44a3855d42be99d4b` passed public dependency
installation into disposable paths, real-inventory `--list-hosts` limited to
`pipeline-dnd`, `--syntax-check`, and `git diff --check`. Its commit was not
pushed. Seriatim and native collection pins remain unchanged, and manifests
across the three repositories agree.
The local integration harnesses converged only the development installation;
there was no operational deployment or live inference, transcription, or object
storage call. Vault values and target access were not needed or verified.
After the override harness passed, a formatting-only split of its fixture JSON
line was checked with `bash -n`, JSON parsing, and `git diff --check` without
rerunning the long integration harness. Independent review subsequently found
the three issues resolved below. No tagged release was created.
## Remediation Follow-up
The three independent-review findings are resolved; see
[remediation evidence](../remediation.md). Public pipeline `37b1cf6` and
collection `b3bc045` remove default-identity assertions and correct migration
and credential guidance. Local consumer `15f0f4e` selects the corrected public
snapshot. Shell/whitespace checks, pipeline and installed-collection syntax and
lint, collection build/install, and real-inventory consumer target/syntax checks
passed. Full host-mutating convergence was not rerun for these documentation
and test-only changes. Application versions/defaults and runtime behavior are
unchanged.
## Closeout
Closed on 2026-09-29 after independent review and resolution of all three
findings. This completes the agreed application upgrade sequence. The active
implementation plan is retired; no additional implementation is required for
this feature. Consumer commits remain local. Operational upgrade, session
migration, live production/testing checks, and any new tagged release require
separate operator action and were not performed as part of closeout.
## Upstream References
- [Audita v2 migration](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.1/docs/migrations/v2.md)
- [Audita configuration](https://gitea.maximumdirect.net/eric/audita/src/tag/v2.0.1/docs/config.md)
- [Narratio v3 release](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/releases/v3.0.0.md)
- [Narratio operations and migration](https://gitea.maximumdirect.net/eric/narratio/src/tag/v3.0.0/docs/operations.md)
- [Notarius v0.8.0 migration](https://gitea.maximumdirect.net/eric/notarius/src/tag/v0.8.0/docs/releases/v0.8.0.md)
- [Scriptorium v0.14.0 migration](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.14.0/docs/releases/v0.14.0.md)

View File

@@ -0,0 +1,206 @@
# Feature 0023: Adopt Narratio v3.1.0 and Forward Scriptorium Credentials
Status: done
## Summary
Update the standalone Narratio role and D&D pipeline to Narratio v3.1.0 and
expose its Scriptorium credential list. Deliver the coordinated change through
the collection and existing deployment consumer without deploying to a host.
## Problem or Opportunity
The operator's deployment to `pipeline-dnd` failed during trim bounds generation
with Scriptorium reporting HTTP 401. Narratio v3.0.0 filtered provider keys out
of the child environment without offering a public Scriptorium credential
selection. Analyze had the same forwarding gap. Provisioning a key through
Ansible alone could not repair that boundary.
Upstream has released explicit Scriptorium credential forwarding in v3.1.0.
The original report is preserved in Narratio commit `9389f69`;
the upstream change is `44a3186`, with release documentation at `40cbf42`.
These are planning references, not substitutes for the released application tag.
## Scope
- Adopt Narratio v3.1.0 in the standalone role and suite version selections.
- Expose its native credential-list field through the standalone role and
supply overrideable D&D defaults through the pipeline role.
- Refresh the Narratio role dependency, public pipeline subtree snapshot,
collection dependency manifest, and existing consumer pins together.
- Extend existing configuration/composition coverage and document operator
credential requirements and normal retry behavior.
## Non-goals
- Changing upstream applications, other application versions, models, prompts,
profile selections, or the existing filesystem and credential-storage policy.
- Adding a credential loader, wrapper, environment file, provider discovery,
or per-stage credential-selection interface.
- Live inference, deployment to a controller or `pipeline-dnd`, credential
verification against providers, or modifying Vault contents.
- Publishing new Ansible release tags or collection release artifacts.
- Reimplementing upstream credential forwarding, redaction, or checkpoint
behavior in Ansible or its test suites.
## Target End State
### Standalone Narratio role
`narratio_version` defaults to `v3.1.0`. The optional public variable
`narratio_scriptorium_credentials` defaults to null, is documented as a list
of strings, and renders `scriptorium.credentials` in the native root pipeline
file only when non-null. An explicit empty list renders `credentials: []`;
nonempty lists preserve the caller's exact credential names. Include the field
in the enclosing Scriptorium-section condition so it works independently of
other optional Scriptorium variables. No provider-specific default belongs in
the standalone role.
### D&D pipeline policy
`dnd_pipeline_narratio_version` selects `v3.1.0`.
`dnd_pipeline_narratio_scriptorium_credentials` defaults to
`[OPENROUTER_API_KEY]` and is passed through the existing Narratio dependency
variables. Inventory can replace the list, including with `[]`, or set null
to omit the field through the standalone role's interface.
The testing overlay inherits this list; no duplicate testing-specific setting
is needed for the currently selected profiles. The existing Notarius reference
to the same key remains independent. Operators selecting different providers
can supply the corresponding names through the ordinary inventory interface.
Credential bytes continue to come from Narratio's process environment or its
existing secrets mechanism. `dnd_pipeline_secrets` remains an optional managed
file-provisioning mechanism, not the only valid credential source. No new secret
file or migration is needed where `OPENROUTER_API_KEY` is already provisioned.
### Upstream contract and operator handoff
Narratio calls the field `pipeline.scriptorium.credentials` internally; the
root pipeline YAML uses `scriptorium: {credentials: [...]}` without an extra
`pipeline:` wrapper. The list applies to trim, analyze (including character
families), and render-debug calls. It forwards names and resolved values without
overriding Scriptorium's own provider/profile selection.
Upstream resolves selected names to nonempty values at configuration load,
including for commands that do not execute Scriptorium. Tests and operator
guidance must account for that existing contract. Omitted/null/empty lists
forward nothing; a native overlay replaces the full list. After upgrading and
provisioning the selected key, retry failed trim/analyze normally; do not force
successful work solely because a credential was added or rotated. See the
upstream references below for the authoritative behavior.
## Repository Ownership
- `ansible-role-narratio`: version default, public variable, argument spec,
template, documentation, and focused configuration tests.
- `ansible-role-dnd-pipeline`: suite version/credential defaults, dependency
wiring and pin, documentation, and composition coverage.
- `ansible-collection-dnd`: exact public pipeline subtree import, matching
dependency manifest, and installed-artifact validation.
- `rakestraw-ansible`: updated consumer dependency pins and concise upgrade
guidance only; preserve its minimal playbook, inventory, and Vault content.
- Workspace: feature tracking, later staged plan, and review evidence.
- Narratio and the remaining applications/assets: read-only upstream contracts.
## Constraints and Settled Decisions
Follow the [Ansible](../../ansible.md), [testing](../../testing.md), and
[planning](../../planning.md) policies and the [MVP architecture](../mvp.md).
Preserve generic application roles versus opinionated suite policy. Reuse the
existing declarative source-build and template tasks; add no production checks.
Required dependency commits must be public before external consumer use; subtree
imports use public Gitea, not sibling paths. Do not alter unrelated pins.
## Simplest Viable Implementation
Add one nullable standalone configuration variable and its ordinary template,
argument-spec, and documentation entries. Add one suite default and dependency
mapping. Advance the Narratio version and coordinated dependency pins, then
reuse the existing collection import and consumer refresh workflow. No new
production task or persistent state is needed.
## Acceptance Criteria
- The standalone role and assembled suite build the released v3.1.0 source.
Any version assertion explicitly supplies the version under test rather than
freezing the current default.
- Representative explicit credential names reach the deployed native
configuration; null omission and explicit `[]` are supported. Extend existing
cases rather than adding a separate exhaustive matrix.
- Suite composition preserves an explicitly supplied credential list in base
and testing configurations. Use synthetic credential values for offline
native validation; do not assert today's default list as a permanent invariant.
- The real role and installed collection pass their existing relevant
validation, including immediate repeated convergence with no changes.
Credential-forwarding internals and provider authentication remain upstream
responsibilities; no live service or new subprocess simulation is required.
- Collection and consumer manifests resolve the coordinated public revisions;
consumer host listing/syntax checks work without deployment or Vault
decryption. Leave the existing hosts-and-roles playbook unchanged.
- Guidance explains load-time credential requirements, existing environment or
file provisioning, dependency refresh, and ordinary retry after the fix.
## Dependencies and Follow-up Work
The public Narratio v3.1.0 tag was verified on 2026-09-29 at
`40cbf4243838b0a1db6caf4c8f790d914ccb96cc`, matching the reviewed release
documentation and configuration contract. The release prerequisite is satisfied.
Use that release rather than substituting a moving branch.
The completed staged implementation plan is preserved in Git history.
Required Ansible dependency commits are public as recorded below. Operational
deployment and a paid/live smoke run remain separate operator activities, not
feature-completion gates.
## Implementation Evidence
Implementation completed on 2026-09-29. The public Narratio role revision is
`758aed7a74c9a64ad02e13ff551b4f7aea16b3af`; the public D&D pipeline role
revision is `0f841fd91ffc533aeec0ec688e81c24bd187a845`; the public
collection revision is `002e86c9deb90820a2f1c2f55e1f4d8be59b7c96`.
The consumer revision `67cc22f37f042fa12ada09547efa677022242284` is
committed locally and not published, preserving its earlier local commits.
The collection's imported pipeline Git tree exactly matches the public source
revision. No release tag or artifact was created.
The Narratio role, pipeline role, and collection each passed `bash -n
tests/integration`, their full `./tests/integration` harnesses, and `git diff
--check`. The role and collection harnesses passed on their first runs. The
pipeline harness's first run encountered a public Git HTTPS timeout; an
unchanged retry passed, including native base/testing configuration inspection
and a zero-change repeat. The consumer installed the collection manifest's D&D
dependencies and exact collection revision in disposable paths; `--list-hosts`
selected only `pipeline-dnd`, `--syntax-check` passed, and `git diff --check`
passed. No operational controller or target host was contacted.
No implementation scope deviation was needed. Offline configuration and
convergence checks do not prove that the
operator's actual key is valid or that a live trim request will succeed.
## Independent Review and Closeout
Closed on 2026-09-29 after independent review found no actionable code-quality
issues or implementation gaps. Null omission, explicit empty lists, suite
credential selection, testing-overlay inheritance, and coordinated dependency
pins match the approved feature. No additional production machinery was added.
The imported pipeline Git tree matches the authoritative source exactly.
Independent shell syntax, whitespace, role syntax/lint, collection build/install,
public role dependency installation, and real-inventory consumer target/syntax
checks passed. Review used the recorded full integration and clean-repeat
results rather than rerunning host-mutating convergence. No operational host or
live provider was contacted. No remediation document change was needed.
The active plan is retired. Consumer and workspace commits remain local;
operational deployment and provider-key validity remain outside this closeout.
## Open Questions
None identified.
## Upstream References
- [Narratio v3.1.0 release notes](../../../../narratio/docs/releases/v3.1.0.md)
- [Scriptorium credentials](../../../../narratio/docs/config.md#scriptorium-credentials)
- [401 troubleshooting](../../../../narratio/docs/troubleshooting.md#scriptorium-returns-http-401-during-trim-or-analyze)

View File

@@ -0,0 +1,62 @@
# Feature <ID>: <Title>
Status: proposed
## Summary
State the selected unit of work and the outcome it enables.
## Problem or Opportunity
Describe why this feature is needed and the current limitation it addresses.
## Scope
- List behavior and deliverables included in this feature.
## Non-goals
- List adjacent behavior intentionally excluded from this feature.
## Target End State
Describe the observable repository, deployment, and operator state after the
feature is complete. Keep this independent of the implementation sequence.
## Repository Ownership
Identify every repository involved and the durable responsibility each one
owns. Distinguish repositories that will change from read-only sources of
application contracts.
## Constraints and Settled Decisions
Link the MVP roadmap and applicable decision records. Record technical or
operational constraints that implementations must preserve.
## Simplest Viable Implementation
Outline the direct, module-driven task flow at the level needed to constrain
the implementation without turning the roadmap into an execution plan. Trust
module idempotence and change detection. Identify any non-obvious probe,
sidecar state, staging mechanism, command, or abstraction and tie it to a
specific acceptance criterion.
## Rationale and Alternatives
Explain material tradeoffs and why the selected end state is preferred. Omit
this section when the choice is mechanical and needs no durable rationale.
## Acceptance Criteria
- Define observable, testable conditions required for feature completion.
## Dependencies and Follow-up Work
List prerequisites and explicitly deferred work without expanding this
feature's scope.
## Potential Future Hardening
List worthwhile security or resilience improvements that are deliberately not
part of the initial implementation. Omit this section when there are none.

View File

@@ -0,0 +1,129 @@
# Implementation Plan <ID>: <Title>
Status: proposed
Target executor: GPT-5.6-Terra
Feature roadmap: `docs/roadmap/features/<id>-<slug>.md`
Active plan location: `docs/roadmap/implementation.md`
## Objective
Summarize the implementation outcome. The feature roadmap remains authoritative
for scope, rationale, target end state, and acceptance criteria.
## Execution Rules
- Execute stages in numeric order.
- Number stages with consecutive integers beginning with `Stage 1`. Do not use
zero-based, decimal, nested, or nonsequential stage identifiers.
- Before each stage, confirm its preconditions and the working-tree state of
its owning repository.
- Before each stage, read every document listed in that stage's Required Policy
Review. Do not rely on policy recalled from an earlier stage.
- Preserve unrelated and pre-existing changes.
- Do not make unresolved product or architecture decisions during execution;
stop and report the decision required.
- Start from the feature roadmap's simplest viable implementation. Trust
module-provided idempotence, change detection, check-mode behavior, and
error handling rather than reproducing them with preliminary probes or
supplemental state.
- Do not add a task merely for defensive completeness. Every probe, fact,
checksum, custom `changed_when`, shell or command invocation, sidecar state
file, staging layer, or abstraction must be required by an
acceptance criterion and must solve behavior that a direct module does not.
- Run every stage's validation before committing it.
- Commit each completed stage when it leaves the repository in a valid state,
using the commit intent specified by that stage.
- Do not begin a dependent stage after an earlier stage fails validation.
## Starting State and Preconditions
- List required branches, revisions, tools, dependencies, and prior features.
- Identify expected clean or intentionally dirty working trees.
## Repository Scope
- List every repository that may change and the changes it owns.
- List repositories that may be inspected but must remain unchanged.
## Stage 1: <Independently Verifiable Outcome>
### Objective
State the single outcome delivered by this stage.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `<docs/ansible.md, docs/testing.md, and/or docs/planning.md as applicable>`
Replace the placeholder with every specialized policy applicable to this
stage. Include `docs/ansible.md` for Ansible design or implementation,
`docs/testing.md` for test work, and `docs/planning.md` for workspace planning
or progress management. Do not list an inapplicable policy merely for
completeness.
### Preconditions
- List facts that must be true before editing begins.
### Owning Repository
`<repository path>`
### Required Changes
1. Describe concrete behavior to implement, including relevant files or
components where known.
2. State invariants, compatibility requirements, and explicit exclusions.
3. Give the expected module-driven task flow. Call out every required use of
`command`, `shell`, state inspection, or manual change detection.
### Validation
Run:
```text
<exact validation command>
```
Expected result: describe the required observable outcome, not merely a zero
exit code.
### Completion Criteria
- List the evidence required before this stage is complete.
### Commit
Commit intent: `<type and concise purpose>`
## Stage 2: <Next Independently Verifiable Outcome>
Repeat the complete stage structure above. Add, remove, or split stages so
each is ordered by dependency, reviewable on its own, and small enough to
diagnose without repeating unrelated work. Continue with `Stage 3`, `Stage 4`,
and subsequent consecutive integers as needed.
## Final Validation and Handoff
- Run cross-stage and cross-repository validation required by the feature
roadmap.
- Confirm every changed repository is clean and identify all resulting commit
hashes.
- Summarize deviations from this plan, unresolved findings, and deferred work.
- Report any implementation complexity added beyond the planned task flow and
the acceptance criterion that required it.
- Do not mark the feature `done`; implementation results require review first.
## Progress Notes
Keep only concise current state, completed stage references, and blockers here.
Git history and implementation commits should preserve detailed execution
evidence.

View File

@@ -0,0 +1,12 @@
# Implementation Plan
No implementation plan is currently active.
[Feature 0023](features/0023-narratio-scriptorium-credentials.md) was closed on
2026-09-29 after implementation and independent review with no actionable
findings. Its roadmap retains the completion evidence; Git history preserves
the completed staged implementation plan.
Discuss and select the next unit of work before preparing another plan.
Operational deployment and live provider validation remain separate operator
activities and are not authorized by this notice.

View File

@@ -14,8 +14,10 @@ Build independently usable Ansible roles for the five Narratio applications
and compose them through a suite-level role developed in its own repository. 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 `rakestraw.dnd` collection exposes that role as `rakestraw.dnd.pipeline`.
The suite-level role installs and configures the complete D&D transcript The suite-level role installs and configures the complete D&D transcript
processing pipeline on a single supported host. Human operators invoke processing pipeline on a single supported host. Operators or unattended
Narratio commands directly to process D&D session recordings and produce automation invoke Narratio commands either under the dedicated `narratio`
runtime identity or under an explicitly selected existing human account that
belongs to the `narratio` group, processing D&D session recordings into
transcripts and related artifacts. transcripts and related artifacts.
## Locked Decisions ## Locked Decisions
@@ -50,17 +52,23 @@ role will manage the native configuration needed to connect to it.
- Released roles build an explicitly selected application release tag. - Released roles build an explicitly selected application release tag.
Development may override the selected revision with a branch or commit. Development may override the selected revision with a branch or commit.
- Source checkouts reside at `/usr/local/src/<app>` and are owned by `root`. - Source checkouts reside at `/usr/local/src/<app>` and are owned by `root`.
- Roles build into a staging location, validate the result, and then install - Roles build and install the binary at `/usr/local/bin/<app>` with
the binary at `/usr/local/bin/<app>` with `root:root` ownership and mode `root:root` ownership and mode `0755`, using the application's native build
`0755`. A failed build must not replace a working installed binary. command and the simplest clear Ansible task flow.
- Builds use the application repository's own build contract, including any - Builds use the application repository's own build contract, including any
application-specific version-injection linker flags. The common baseline is application-specific version-injection linker flags. The common baseline is
`GOWORK=off`, `GOTOOLCHAIN=local`, `CGO_ENABLED=0`, and `-trimpath`. `GOWORK=off`, `GOTOOLCHAIN=local`, `CGO_ENABLED=0`, and `-trimpath`.
- Build state must account for the checked-out commit, Go toolchain, and build - Roles normally rebuild when the Git task reports a changed checkout or the
arguments so that roles rebuild when a relevant input changes rather than binary is absent. An application-level version or smoke check may add a
relying only on the existence of the installed binary. trigger only when its feature specification explicitly requires that
- Each application role exposes variables for its repository, selected production behavior. Roles do not maintain fingerprints, checksums, or
version or revision, source directory, binary path, and build settings. sidecar build-state files for the MVP.
- Each application role exposes variables only for meaningful consumer
choices, normally including its repository, selected version or revision,
source directory, binary path, dependency management, Go Snap channel, and a
build-tool path when dependency opt-out permits another provisioning
mechanism. Fixed details of the upstream build contract need not become
public variables.
### Go toolchain ### Go toolchain
@@ -98,10 +106,26 @@ role will manage the native configuration needed to connect to it.
- The collection bundles and exposes the independently developed suite-level - The collection bundles and exposes the independently developed suite-level
role as `rakestraw.dnd.pipeline`, providing one opinionated interface for role as `rakestraw.dnd.pipeline`, providing one opinionated interface for
consumers. consumers.
- The collection incorporates the pipeline role at `roles/pipeline` as a
squashed Git subtree. The standalone pipeline repository remains
authoritative; maintainers change and validate the role there, then import
a reviewed commit into the collection rather than editing the subtree copy.
- The subtree makes the collection artifact self-contained for its bundled
role without requiring submodule initialization, symbolic links, sibling
repositories, or custom synchronization tooling.
- The pipeline role owns compatible application-version selection, - The pipeline role owns compatible application-version selection,
cross-application configuration, D&D campaign deployment, prompt-library cross-application configuration, D&D campaign deployment, prompt-library
deployment, operator access, the pipeline-wide secret-delivery policy, and deployment, operator access, the pipeline-wide secret-delivery policy, and
end-to-end validation. end-to-end validation.
- Unlike the generic standalone roles, the pipeline role deliberately supplies
opinionated, D&D-specific defaults for all five applications. It expresses
that policy through the standalone roles' existing field-specific variables,
keeps those values overrideable through ordinary inventory precedence, and
does not duplicate the application roles' templates or convergence logic.
- Pipeline defaults represent policy deliberately selected for the D&D suite;
they do not mirror every upstream application default. Settings for which the
suite has selected no policy remain under the application or caller's
control.
- The pipeline role uses the Git-hosted standalone application roles as - The pipeline role uses the Git-hosted standalone application roles as
dependencies. This is an intentional choice for the controlled project dependencies. This is an intentional choice for the controlled project
environment despite the additional repository and dependency structure and environment despite the additional repository and dependency structure and
@@ -110,6 +134,22 @@ role will manage the native configuration needed to connect to it.
that installs both the collection and its standalone role dependencies; a that installs both the collection and its standalone role dependencies; a
plain collection installation is not assumed to resolve arbitrary Git role plain collection installation is not assumed to resolve arbitrary Git role
dependencies by itself. dependencies by itself.
- The standalone application roles use the canonical installed names
`rakestraw.audita`, `rakestraw.narratio`, `rakestraw.notarius`,
`rakestraw.seriatim`, and `rakestraw.scriptorium`.
- The pipeline role supplies a root `requirements.yml` bootstrap manifest for
those Git-hosted roles and a collection requirements manifest for shared
collection dependencies. During active development, the Git roles are
pinned to reviewed commits; released manifests replace those commits with
immutable role release tags.
- The collection supplies one consumer-facing root `requirements.yml` that
combines those same Git-hosted role pins with the shared collection
dependencies. Its Galaxy metadata separately declares the native collection
dependencies that Ansible can resolve while installing a collection.
- The pipeline role composes the five roles through ordinary Ansible role
dependency metadata. It exposes suite-prefixed variables for the small set
of values the suite must coordinate, and does not duplicate every downstream
role variable behind a parallel alias.
This design keeps repository ownership and change blast radius aligned with This design keeps repository ownership and change blast radius aligned with
the independently released applications while retaining a single opinionated the independently released applications while retaining a single opinionated
@@ -119,8 +159,11 @@ application-role releases in one source repository.
### Ansible dependencies and task structure ### Ansible dependencies and task structure
- The standalone application roles are self-contained and use - The standalone application roles are independently usable and prefer
`ansible.builtin` modules directly. `ansible.builtin` modules where they directly fit the task.
- `community.general` is treated as a stable, supported dependency. Roles may
freely select its modules when appropriate, provided the collection
dependency is declared and pinned for reproducible installation and tests.
- The roles do not depend on the private - The roles do not depend on the private
`maximumdirect.core.ansible_role_loader` role used by the proof of concept. `maximumdirect.core.ansible_role_loader` role used by the proof of concept.
- Platform-specific task selection may be added later using ordinary Ansible - Platform-specific task selection may be added later using ordinary Ansible
@@ -128,18 +171,36 @@ application-role releases in one source repository.
- Small amounts of repeated prerequisite or installation logic are acceptable - Small amounts of repeated prerequisite or installation logic are acceptable
during the MVP. A shared helper role or collection plugin should be during the MVP. A shared helper role or collection plugin should be
introduced only if substantial, stable shared behavior emerges. introduced only if substantial, stable shared behavior emerges.
- Ansible modules are trusted to implement their documented state transitions,
idempotence, and change detection. Roles do not add preliminary existence
checks, manual comparisons, or supplemental state around a module that
already owns the desired behavior.
- State gathering is appropriate only when it controls behavior outside the
responsible module's contract, such as deciding whether an application
binary must be rebuilt.
### Dependency and release reproducibility ### Dependency and release reproducibility
- Development dependency manifests may temporarily refer to branches or - Development dependency manifests may temporarily refer to branches or
commits while the roles are changing rapidly. commits while the roles are changing rapidly.
- The projects' public repositories beneath
`https://gitea.maximumdirect.net/eric/` are the authoritative release
sources. Standalone roles are published through immutable Git tags.
- Every released dependency manifest must pin each Git-hosted role dependency - Every released dependency manifest must pin each Git-hosted role dependency
to an immutable role release tag. to an immutable role release tag.
- The collection release is the compatibility record for the exact set of - The collection release is the compatibility record for the exact set of
application-role versions it composes. application-role versions it composes.
- A collection release consists of its immutable repository tag, matching
Gitea release, and the `ansible-galaxy collection build` archive produced
from that tagged tree and attached to the Gitea release.
- Collection integration tests must install and exercise the same pinned role - Collection integration tests must install and exercise the same pinned role
combination delivered to consumers, starting from an environment in which combination delivered to consumers, starting from an environment in which
the dependencies are not already installed. the dependencies are not already installed.
- Collection integration tests build and install the collection artifact into
isolated Ansible paths, resolve `rakestraw.dnd.pipeline`, validate one
representative assembled deployment through native application interfaces,
and confirm immediate convergence. Detailed pipeline feature matrices remain
the standalone pipeline role's testing responsibility.
- Updating one application role in the suite requires updating its pinned - Updating one application role in the suite requires updating its pinned
version in the collection, validating the assembled suite, and releasing a version in the collection, validating the assembled suite, and releasing a
new collection version. Unrelated application-role repositories remain new collection version. Unrelated application-role repositories remain
@@ -149,29 +210,175 @@ application-role releases in one source repository.
- The pipeline role installs Narratio's PromptKit-compatible prompt library - The pipeline role installs Narratio's PromptKit-compatible prompt library
from the `narratio-prompts` Git repository. The Scriptorium role owns its from the `narratio-prompts` Git repository. The Scriptorium role owns its
native prompt, profile, and schema directory configuration, while the native prompt and schema directory configuration, while the pipeline role
pipeline role owns populating those locations with suite integration owns populating those locations with suite integration content.
content.
- The upstream repository is - The upstream repository is
`https://gitea.maximumdirect.net/eric/narratio-prompts`. `https://gitea.maximumdirect.net/eric/narratio-prompts.git`.
- For the MVP, the pipeline role tracks and pulls the latest upstream commit. - The repository is checked out at
`/usr/local/share/narratio/prompt-library` by default. Scriptorium's prompt
and schema directories are the checkout's `prompts/` and `schemas/`
subdirectories.
- The repository does not currently contain execution profiles. The pipeline
role does not set Scriptorium's profile directory until a later suite-policy
feature selects and deploys profiles.
- For the MVP, the pipeline role tracks and pulls the repository's `main`
branch. The origin, revision, and checkout root are configurable, and a
caller may select an immutable commit when required.
- Pinning the prompt library to a version or release is deferred until the - Pinning the prompt library to a version or release is deferred until the
upstream repository provides versioned releases. upstream repository provides versioned releases.
### Campaign registry content
- The pipeline role checks out the `campaigns` Git repository directly into
Narratio's campaign registry root. The upstream repository is
`https://gitea.maximumdirect.net/eric/campaigns.git`.
- The default campaign root remains
`/usr/local/share/narratio/campaigns`, and the pipeline role passes that same
value to the Narratio application role.
- For the MVP, the pipeline role tracks and pulls the repository's `main`
branch. The origin, revision, and campaign root are configurable, and a
caller may select an immutable commit when required.
- Both asset checkouts are root-managed and remotely authoritative. Operators
may read the content but do not edit it on the managed host. Ordinary Git
module convergence owns tracked-content updates; the role does not maintain
separate revision state or purge untracked files.
### Accounts, ownership, and operator access ### Accounts, ownership, and operator access
- The roles create a dedicated `narratio` user and `narratio` group as needed. - The standalone Narratio role creates a dedicated system `narratio` user and
- The `narratio` account owns Narratio's writable runtime directories. `narratio` group. The account uses `/var/lib/narratio` as its default home
and has a non-login shell.
- 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 - Application source trees and installed binaries are owned by `root` and are
not writable by operators or the runtime account. not writable by operators or the runtime account.
- Ordinary human users run `narratio run` and other Narratio commands directly. - The supported operational model runs `narratio run` and other processing
- Those operators receive the required access by membership in the `narratio` commands either as the dedicated `narratio` account or as an existing human
group. account selected through the pipeline role's
- Managed configuration should be owned by `root`, readable by the `narratio` `dnd_pipeline_operator_users` list. The list defaults to empty.
group where needed, and remain under Ansible control rather than being - Every selected human account must exist before pipeline convergence. The
routinely edited by operators on the host. role adds selected accounts to the runtime group with additive supplementary
- Shared runtime directories must grant the `narratio` group the write access membership and does not create accounts, replace other group memberships,
needed for direct operator invocations. or manage omitted accounts.
- Removing a name from `dnd_pipeline_operator_users` does not revoke existing
membership. Account and access removal remain outside the MVP until an
explicit lifecycle policy is selected.
- Newly granted supplementary membership may require the operator to begin a
new login session before it becomes visible to that session.
- 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 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 lives beneath the conventional
`/usr/local/etc/narratio/secrets` subdirectory owned by
`narratio:narratio`, with directory mode `0750` and file mode `0640`.
Membership in the `narratio` group is an explicit authorization to use the
suite's shared credentials. This deliberately differs from Narratio's
general single-user `0700` and `0600` recommendation while retaining no
world access. Ordinary configuration contains only credential reference
names.
- The pipeline role exposes one empty-by-default credential mapping from valid
environment-variable names to string file contents. Supplied entries manage
the corresponding files; omitted names remain unmanaged. Credential values
are expected to come from encrypted inventory such as Ansible Vault and are
suppressed from task output. Credential removal and directory mirroring are
outside the MVP.
- Narratio's native ConfigKit secrets bootstrap owns loading these files and
process-environment precedence. The suite does not add a wrapper, shell
profile, service environment file, or parallel credential loader.
- The suite coordinates Audita proposal and validation on the
`AUDITA_LLM_API_KEY` reference and selects `OPENROUTER_API_KEY` for
Notarius's production extraction profile. Narratio v2.1.0 resolves those
typed references and forwards only the selected credentials to the
corresponding subprocesses.
- [Decision 0002](../decisions/0002-shared-readable-pipeline-filesystem-policy.md)
records the complete rationale and boundary for this policy.
### Narratio configuration
- The standalone Narratio role manages the canonical root pipeline document
at `/usr/local/etc/narratio/pipeline.yml` through a field-specific public
variable interface.
- The role requires a caller-supplied WhisperX transcription URL because the
field is required by Narratio and has no valid universal deployment value.
- Filesystem roots managed by the role have concrete defaults and are rendered
so application configuration agrees with managed host state. Other optional
application fields default to null, are omitted from the rendered document,
and inherit Narratio's built-in defaults.
- Native open-ended collections such as publish outputs, Notarius references
and outputs, and Scriptorium artifacts and artifact families are exposed as
complete fields. Callers may compose their final values in inventory; the
role does not add merge or precedence behavior.
- The root document may name ConfigKit imports, but the standalone role does
not manage imported fragments or profile overlays. A caller that selects
them owns their deployment.
- Credential fields contain environment-variable names, never secret values.
Secret delivery remains suite-level policy.
- The standalone Narratio role owns the root pipeline document. The pipeline
role owns its D&D-specific imported processing, artifact, and artifact-family
fragments under `/usr/local/etc/narratio` and selects them through an
explicit ordered `configkit.imports` list.
- Each ordinary artifact and artifact family is defined in a separate managed
file. Explicit imports are preferred to directory globs so removed or stale
files do not remain active implicitly.
- The pipeline role manages a native `profiles/testing.yml` overlay for
inexpensive development and asset iteration. Production retains its
frontier-oriented model/profile policy; callers select the testing overlay
explicitly with Narratio's `--profile testing` interface.
- Base fragments and the testing overlay contain configuration and
environment-variable or secret-reference names only. They never contain raw
credentials.
- The D&D suite deliberately supplies Audita's complete reviewed processing
policy, including the current module sequence and tuning, `audita-v1`
output, the `https://inference.ai.rakestrawhome.com/v1` endpoint, and
`google/gemma-4-31b-it` for proposal and validation. Those values remain
inventory-overrideable and are suite policy rather than copies of upstream
defaults.
- The Narratio `testing` profile selects `gemini-flash-latest` for its
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. Narratio v2.1.0 requests reuse
of compatible recorded checkpoints during ordinary extraction; forced
extraction omits checkpoint loading and refreshes the active chunk plan.
- 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.
- The D&D suite selects its Backblaze-compatible S3 archive, typed
`OBJECT_STORAGE_KEY_ID` and `OBJECT_STORAGE_KEY` references, maximum S3 audio
caching, run publication, human-facing transcript and artifact outputs, and
cleanup of successfully published workspace state. Feature 0015 owns the
exact overrideable defaults and publication set.
- Accepted Notarius lane outputs remain addressable inside Narratio as
`narratio.extraction.<output_key>` sources. Future analyze-stage Scriptorium
artifacts may consume those sources directly; publishing an extraction lane
to a stable remote destination is an independent policy choice.
### Execution model ### Execution model
@@ -188,19 +395,26 @@ later design decision changes them:
- `/usr/local/etc/narratio` for Narratio configuration - `/usr/local/etc/narratio` for Narratio configuration
- `/usr/local/etc/audita/config.yml` for Audita configuration - `/usr/local/etc/audita/config.yml` for Audita configuration
- `/usr/local/etc/notarius/config.yml` for Notarius 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/scriptorium/config.yml` for Scriptorium configuration
- `/usr/local/etc/narratio/secrets` for suite-managed restricted credentials
- `/usr/local/share/narratio/campaigns` for version-controlled campaign data - `/usr/local/share/narratio/campaigns` for version-controlled campaign data
- `/usr/local/share/narratio/prompt-library` for version-controlled prompts
and schemas
- `/usr/local/src/<app>` for root-owned application source checkouts - `/usr/local/src/<app>` for root-owned application source checkouts
- `/usr/local/bin/<app>` for root-owned application binaries - `/usr/local/bin/<app>` for root-owned application binaries
- `/var/lib/narratio` for durable workspace and session state - `/var/lib/narratio` for durable workspace and session state
- `/var/spool/narratio` for spool data - `/var/spool/narratio` for spool data
- `/var/cache/narratio` for cached 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 The Narratio role creates and configures the campaign root; the pipeline role
populates it from the selected campaign source. `/usr/local/share` assumes Git populates it from the selected campaign source. `/usr/local/share` assumes Git
is authoritative and operators do not edit campaign content directly on the is authoritative and operators do not edit campaign content directly on the
managed host. The exact prompt-library checkout and installed-content paths managed host. The prompt-library checkout retains its upstream `prompts/` and
remain to be designed. `schemas/` layout at the fixed root above.
## Deferred Beyond the MVP ## Deferred Beyond the MVP
@@ -209,21 +423,17 @@ remain to be designed.
- Installation from prebuilt application release artifacts - Installation from prebuilt application release artifacts
- Deploying or managing WhisperX - Deploying or managing WhisperX
- Versioned Narratio prompt-library releases and pinning - Versioned Narratio prompt-library releases and pinning
- Versioned campaign-content releases and default release pinning
- A role-managed scheduler or persistent Narratio service - A role-managed scheduler or persistent Narratio service
- Cryptographic artifact verification, supply-chain hardening, and protection
against adversarial source or dependency infrastructure
- Transactional binary replacement and preservation of the prior executable
after a local build failure
- Compiler-identity fingerprints, binary checksums, sidecar build-state files,
and recovery from deliberately malformed or redirected managed paths
## Design Work Still Open ## Design Work Still Open
The following areas require investigation and decisions before implementation: The following area requires investigation and decisions before implementation:
- Exact application repository URLs, default release tags, build commands,
version-injection flags, and validation commands
- Standalone role Galaxy names and the dependency-manifest/bootstrap layout
- The mechanism used to incorporate the independently developed pipeline role
into collection releases
- Configuration contracts and filesystem requirements of Notarius, Audita,
Seriatim, and Scriptorium
- The prompt-library destination and its integration with Scriptorium
- Secret injection and storage
- Operator-group membership variables and directory permission details
- Upgrade, downgrade, and removal behavior - Upgrade, downgrade, and removal behavior
- Ansible dependency, validation, and test strategy

144
docs/roadmap/remediation.md Normal file
View File

@@ -0,0 +1,144 @@
# Feature 0022 Remediation Review
Status: resolved
Reviewed on 2026-09-29:
- Pipeline `8ea8621` and `ea8b09e`.
- Collection subtree import through `a78c309` and assembly `3d77eb3`.
- Consumer `f694dad`.
The production wiring implements the approved coordinated versions, Audita
backend/profile assets, credential lists, overlay paths, and nullable retry
controls. The collection's imported pipeline tree exactly matches the source
role. The following test-policy and operator-documentation issues were found
and have now been addressed as recorded below.
Git history preserves the previously resolved Feature 0013 remediation record.
## Finding 1: New assertions freeze unconfigured suite defaults
Priority: P2
Owners: pipeline role and collection tests.
Locations:
- `ansible-role-dnd-pipeline/tests/integration:172`–173.
- `ansible-collection-dnd/tests/integration:104`–105 and 108–109.
The new baseline assertions require specific Audita profile IDs and Narratio
credential lists, but the cases do not explicitly supply the corresponding
selection/list variables. Supplying synthetic values in `dnd_pipeline_secrets`
does not select the credential lists. These assertions therefore fail when
legitimate defaults change, even if installation and caller overrides work.
Required correction: remove redundant default-identity assertions from the
baseline smoke case, or explicitly supply the relevant public inputs and
assert those values. The pipeline already has a useful custom-credential
override case; prefer reusing its coverage. Keep native validation and clean
repeats. Do not replace literals by reading role defaults into expectations;
that would still test implementation identity rather than caller behavior.
This strengthens acceptance beyond the user's state-based testing policy.
The approved plan explicitly asked for supplied-value tests, not default
snapshots.
## Finding 2: Upgrade guidance confuses configuration with session migration
Priority: P2
Owners: pipeline README and consumer deployment guidance.
Locations:
- `ansible-role-dnd-pipeline/README.md:166`–168 and 337–338.
- `rakestraw-ansible/docs/pipeline-dnd.md:86`–104.
The pipeline links “Audita's v2 manifest migration” to Audita's configuration
migration guide, but does not identify Narratio's actual session-manifest
migration. The consumer likewise refers to “Audita manifests” and only
generically warns about Narratio manifests. The roadmap specifically requires
guidance on backing up and migrating local provenance while preserving
progress and immutable snapshots. Existing Narratio manifests containing
`effective_config.selected_profile` are rejected by v3.
Required correction:
- Describe Audita's change as a configuration/backend/profile migration.
- Link Narratio v3's exact operations section
`#migrating-manifest-overlay-provenance`; briefly explain backup and
`effective_config.selected_profile` → `selected_overlay` (or removal as
upstream permits), preserving stage/checkpoint state and leaving immutable
remote snapshots unchanged. Do not add automatic migration or forced reruns.
- Correct or remove the stale claim that Notarius v0.8.1 selects PromptKit
v0.10.0. Its tagged release specifies v0.11.2; prefer linking upstream release
notes over duplicating dependency/catalog versions.
This is a missing operator handoff, not a request for additional runtime code.
## Finding 3: Documentation makes managed secret files mandatory
Priority: P2
Owners: pipeline README and consumer deployment guidance.
Locations:
- `ansible-role-dnd-pipeline/README.md:160`–163.
- `rakestraw-ansible/docs/pipeline-dnd.md:69`–71.
The new text requires each credential to be supplied through
`dnd_pipeline_secrets`. Runtime behavior does not require that: Narratio can
resolve listed names from its process environment or existing secret files.
The README's existing managed-credentials section already describes environment
precedence and an empty default secrets map.
Required correction: require the credential names in the forwarding lists,
but describe managed secret files as the suite-supported provisioning option,
not the only permitted source. Preserve the consumer's chosen Vault workflow
without imposing it on every standalone suite user. No code or new tests are
needed for this wording correction.
This is an unintended documentation-level strengthening of the requirements.
## Review Validation
Shell syntax, changed-commit whitespace checks, pipeline syntax checking with
locally available collections, production-profile lint, and collection build
passed. Source and imported pipeline Git tree hashes match exactly. Reviewed
the recorded successful role/collection integration and consumer syntax runs;
did not rerun host-mutating convergence. A fresh dependency installation stalled
and was stopped, so this review does not independently establish a complete
fresh public dependency installation. No operational host was contacted.
## Remediation Boundaries
Fix authoritative pipeline files first, then publish and re-import the corrected
pipeline revision through the existing public Gitea subtree workflow. Do not
edit its collection copy directly. Update collection-owned tests and consumer
pins/links to the corrected public snapshot as needed. Preserve all agreed
application versions, configuration defaults, and runtime behavior. Validate
affected tests in proportion to the changes; no operational deployment,
credentials, live inference, or session migration is required.
## Resolution Evidence
All three findings were addressed on 2026-09-29:
- Finding 1: pipeline `37b1cf6` removes redundant baseline credential-list
assertions while preserving custom-input coverage; collection `d9abb62`
removes default profile-ID and credential-list assertions. Native profile
inspection, configuration validation, and immediate clean-repeat checks remain.
- Findings 2 and 3: pipeline `37b1cf6` and consumer `15f0f4e` distinguish
Audita configuration migration from Narratio session migration, link the
exact provenance procedure, preserve progress and immutable snapshots,
and allow environment or file-based credential provisioning. The stale
Notarius dependency/catalog claim is replaced by tagged release guidance.
- The public pipeline revision is
`37b1cf6fab71c6a1212e49357c2e825cb0237a00`; collection subtree import and
public revision `b3bc0457efb7ea14ed11789978edd440537860fc` contain its exact
Git tree. Both remote branch heads were independently checked with
`git ls-remote`. Consumer `15f0f4e` selects that collection and links the
corrected source README; the consumer commit remains local.
- Shell syntax and whitespace checks passed. Pipeline and installed-collection
syntax checks and production-profile lint passed. Collection build and
disposable artifact installation passed. Consumer real-inventory host
listing selected only `pipeline-dnd`, and syntax checking passed without
deployment or Vault decryption.
- Validation used the previously downloaded public role dependencies and
available local collections. Full host-mutating integration was not rerun:
production code/defaults are unchanged, test changes remove assertions and
unused parsing, and prior full-run evidence remains applicable to unchanged
behavior. No operational system or session state was modified.

View File

@@ -0,0 +1,282 @@
# Test Suite Audit Findings
Status: resolved
## Executive Summary
All three integration suites pass, and each includes the most important common
behavioral check: an immediate repeated role application reports no changes.
The suites also contain useful coverage of explicitly selected releases,
caller-supplied Go executables, missing-binary recovery, configuration
rendering, native configuration validation, and Notarius pipeline composition.
The suites are nevertheless substantially larger and more implementation-bound
than the workspace testing policy permits. The recurring problems are:
- exact assertions about the current default release and its commit;
- independent verification of ownership, permissions, checkout state, and
template output already managed by trusted Ansible modules;
- parsing Ansible output for specific task names and individual
`changed`/`skipped` results;
- deliberate metadata drift followed by tests of `ansible.builtin.file`;
- three-case negative tests of self-evident platform assertions;
- repeated clean-run assertions after nearly every scenario; and
- duplicated final shell assertions after equivalent Ansible verifiers.
The appropriate remediation is subtraction and consolidation. The retained
suites should exercise stable role-owned behavior through final application
outcomes, with one representative case for each meaningful behavior.
## Baseline
The audit ran on Ubuntu 26.04 `x86_64` with Ansible Core 2.21.3 and
ansible-lint 26.8.0. The role revisions were:
| Repository | Revision | Integration result |
| --- | --- | --- |
| `ansible-role-seriatim` | `fb8dc41` | Pass |
| `ansible-role-audita` | `847c4c3` | Pass |
| `ansible-role-notarius` | `eb4f511` | Pass |
The following commands all exited successfully:
```text
(cd ansible-role-seriatim && tests/integration)
(cd ansible-role-audita && tests/integration)
(cd ansible-role-notarius && tests/integration)
```
Each driver installed its pinned collection requirements into a private
temporary directory, ran a syntax check and production-profile ansible-lint,
executed its behavioral scenarios, and restored its default deployment during
cleanup. The runs emitted non-fatal local-tooling warnings about Python
interpreter discovery or an already installed duplicate collection; these did
not affect the results or any classification below.
All three role repositories were clean before and after the audit. The control
repository began dirty solely because the new testing convention, audit plan,
and status update were awaiting commit.
## Test Inventory
| Repository | Entry point and supporting files |
| --- | --- |
| `ansible-role-seriatim` | `tests/integration`, `tests/inventory`, `tests/converge.yml`, `tests/verify.yml`, `tests/unsupported.yml`, `collections/requirements.yml`, and the README validation section |
| `ansible-role-audita` | `tests/integration`, `tests/inventory`, `tests/converge.yml`, `tests/verify.yml`, `tests/verify-config.yml`, `tests/unsupported.yml`, `collections/requirements.yml`, and the README validation section |
| `ansible-role-notarius` | `tests/integration`, `tests/inventory`, `tests/converge.yml`, `tests/verify.yml`, `tests/verify-config.yml`, `tests/unsupported.yml`, `collections/requirements.yml`, and the README validation section |
## Cross-Repository Findings
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
| --- | --- | --- | --- | --- | --- |
| All three | Pinned collection installation, syntax check, and ansible-lint | Static validity and reproducible dependencies | Retain | Keep as static validation before behavioral scenarios. | These checks complement rather than duplicate behavioral testing. |
| All three | `require_clean_recap` after an immediate repeat | Role-level repeated convergence | Retain | Keep at least one immediate clean repeat per role and repeats specifically required after missing-binary recovery. | Overall `changed=0` is a first-class public role outcome. |
| All three | `require_changed_recap` after each mutating setup | Ansible reports some change on the first run | Remove | Stop asserting a nonzero aggregate change count except where a future requirement specifically makes reporting itself significant. | Final application state is the behavior of interest; these checks add little beyond successful convergence and make scenario sequencing brittle. |
| All three | Greps for named build, metadata, and configuration tasks | Current task names and individual `changed` or `skipped` results | Remove | Delete all task-output parsing. | These are direct implementation traces and fail under behavior-preserving task refactors. |
| All three | Binary/source/configuration ownership and mode assertions | Postconditions declared to `file`, `git`, and `template` | Remove | Delete independent metadata and recursive-ownership verification. | These tests re-prove trusted module behavior rather than role-authored decisions. |
| All three | Binary mode mutation followed by convergence | `ansible.builtin.file` repairs mode drift without building | Remove | Delete the scenario. | It is a focused regression test for the built-in file module and current task arrangement. |
| All three | Debian, old Ubuntu, and unsupported-architecture matrix | Straightforward platform assertion branches | Remove | Delete `tests/unsupported.yml` and the three-case driver loop. | The declarative assertion is self-evident and does not warrant a negative matrix. |
| All three | Restoration of the current default followed by verification and another repeat | Test cleanup and the current default identity | Simplify | Keep one best-effort cleanup convergence, but do not treat it as another test or assert the restored release value. | Cleanup is useful; testing a mutable default and repeating already established idempotence are not. |
| All three | Final shell assertions duplicating earlier verifiers | Current commit, metadata, version, or config state | Remove | Delete duplicate end-of-driver assertions. | They add maintenance cost without protecting a distinct behavior. |
## Seriatim Classification
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
| --- | --- | --- | --- | --- | --- |
| Seriatim | Default convergence | The role can be applied with its default interface | Retain | Keep as a smoke test without asserting the exact default tag, commit, or filesystem metadata. | A default invocation is useful even though the present default value is not a stable test expectation. |
| Seriatim | Default `v1.5.0` and commit verification | Present default release identity | Remove | Remove the fixed `default_commit` and exact default-version assertions. | This is a change detector; advancing the supported default should not break unrelated tests. |
| Seriatim | Baseline immediate repeat | Clean convergence | Retain | Keep the overall `changed=0`, `failed=0` check. | This directly expresses the agreed idempotence requirement. |
| Seriatim | Missing binary | The imperative build runs when its output is absent and then converges | Simplify | Delete the binary, apply the role, verify the executable through `--version`, and require the next run to be clean; remove task-name greps. | The binary-existence trigger is role-authored behavior, while the current task name and status are not. |
| Seriatim | Dependency opt-out and custom Go executable | The caller-supplied build executable is honored | Simplify | Retain the wrapper invocation evidence, preferably combined with the missing-binary scenario; remove build-task greps and fixed-default assertions. | The selected build executable is a public role choice that cannot be observed reliably from the final binary alone. |
| Seriatim | Binary metadata repair | Built-in file convergence | Remove | Delete the complete scenario. | It tests `ansible.builtin.file`, not Seriatim-specific behavior. |
| Seriatim | Explicit `v1.4.0` selection | A caller-selected immutable release is installed | Simplify | Retain explicit `seriatim_version: v1.4.0` and verify `seriatim version v1.4.0`; remove the expected commit and task-state assertions. | This is the stable version-selection test described by the testing convention. |
| Seriatim | Restore `v1.5.0` default | Cleanup plus present default identity | Simplify | Reduce to cleanup only. | Exact current-default verification duplicates the harmful baseline snapshot. |
| Seriatim | Platform failure matrix | Distribution, release, and architecture assertions | Remove | Delete the matrix and `tests/unsupported.yml`. | No plausible role regression justifies separately testing each simple assertion. |
| Seriatim | `tests/verify.yml` installation contract | Commit, source metadata, binary metadata, and version | Replace | Replace the broad verifier with a narrow native version check used for an explicitly selected tag. | Only the application outcome is valuable; the remaining assertions repeat trusted modules. |
| Seriatim | README validation claims | Description of the current large matrix | Replace | Describe the lean retained behaviors after remediation. | Documentation should not promise deleted implementation-trace and module tests. |
## Audita Classification
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
| --- | --- | --- | --- | --- | --- |
| Audita | Default convergence | The role installs and configures successfully through its default interface | Retain | Keep as a smoke test and validate the resulting configuration with Audita; do not inspect exact default identity or metadata. | Successful native validation is an application outcome and does not freeze the default document. |
| Audita | Default commit assertion | Present default checkout identity | Remove | Delete `default_commit` and exact commit verification. | It is both a mutable-default snapshot and a re-test of `ansible.builtin.git`. |
| Audita | Source, binary, and configuration metadata | Trusted module postconditions | Remove | Delete the ownership, permission, regular-file, and executable assertions. | The role directly declares these states with trusted modules. |
| Audita | Exact minimal default document `{"version": 1}` | Current default rendering | Remove | Do not snapshot the complete default document. Test null omission with explicitly supplied inputs in a representative configuration case instead. | A future intentional concrete default would otherwise cause an unrelated failure. |
| Audita | Native validation of the managed configuration | The role produces configuration Audita accepts | Retain | Keep one native validation for default smoke coverage and one for the representative explicit configuration. | This observes application behavior rather than reconstructing its schema. |
| Audita | Baseline immediate repeat | Clean convergence | Retain | Keep one role-level clean repeat. | This is required public behavior. |
| Audita | Missing binary | Absent build output is recreated and convergence resumes | Simplify | Retain recovery and the following clean repeat; prove usability with the Audita CLI and remove task-output greps. | The imperative build trigger is role logic, but its task name is not. |
| Audita | Dependency opt-out and custom Go executable | Caller-selected compiler path is used | Simplify | Retain wrapper invocation evidence and combine it with missing-binary recovery; remove task greps and redundant repeat runs. | This covers a documented public choice with one representative case. |
| Audita | Binary metadata repair | Built-in file convergence | Remove | Delete the complete scenario. | It tests Ansible's file module. |
| Audita | Representative configuration containing nearly every field | Field-to-YAML mapping, nested sections, and native validity | Simplify | Use a smaller explicit sample spanning representative scalar, list, nested, and duration shapes. Assert only selected paths and specifically selected omissions, then run native validation. | Full-document equality across nearly every field unnecessarily ossifies the template and public interface. |
| Audita | Explicit falsey configuration | Empty lists and strings are rendered rather than omitted | Retain | Keep representative falsey values, preferably in the same explicit configuration scenario, and assert only the affected paths. | The null-versus-falsey distinction is role-authored and easy to regress. |
| Audita | Configuration task changed while build task skipped | Configuration changes independently of installation | Remove | Delete task-name and status inspection. Confirm the rendered application behavior and successful convergence instead. | Whether named tasks ran is an implementation detail; the ordinary `when` expressions are suitable for review and lint. |
| Audita | Restore the minimal default configuration | Cleanup and exact current default | Simplify | Keep restoration only as cleanup and remove fixed-document, fixed-commit, task-state, and extra repeat assertions. | It does not add a distinct stable behavior. |
| Audita | Alternate raw commit `46b7356...` | A non-default Git revision can be selected | Replace | Remove the raw-commit case. Add an explicit immutable-release test only when Audita exposes a stable native way to identify the installed application release. | A raw source commit checked with `git rev-parse` tests checkout mechanics, not the installed application's release. Audita currently has no `--version` or `version` command, and tags `v0.9.0` and `v0.9.1` both resolve to `a84941d...`, so neither tag provides a distinguishable installed outcome today. |
| Audita | Platform failure matrix | Straightforward platform assertions | Remove | Delete the matrix and `tests/unsupported.yml`. | This is expressly outside the testing house style. |
| Audita | Final commit, metadata, and config checks | Duplicate checkout/module/validation assertions | Remove | Delete them. | Equivalent checks already ran, and most should themselves be removed. |
| Audita | `tests/verify.yml` broad installation contract | Commit, metadata, default document, and native config validity | Replace | Reduce it to native configuration validation; move explicit field assertions to the focused representative verifier. | Only native validity is a stable application outcome in this verifier. |
| Audita | README validation claims | Description of default, metadata, rebuild, and platform tests | Replace | Describe only the retained static checks and behavioral scenarios. | The present prose promises low-value coverage that should be removed. |
### Audita Version-Coverage Gap
The current suite does not—and with the present application interface cannot—
perform the useful test “select immutable release X and verify that the
installed Audita reports X.” Running either `audita --version` or
`audita version` fails as an unknown command. The recommended role-test
remediation is to remove the misleading raw-commit scenario rather than
replace it with another Git-module assertion. A native Audita release-identity
command would enable the desired explicit-version test later, but adding that
application feature is outside this audit and should be selected separately.
## Notarius Classification
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
| --- | --- | --- | --- | --- | --- |
| Notarius | Default convergence | The default public interface installs and configures successfully | Retain | Keep as a smoke test, run `notarius --version` without fixing its output to the current default, and validate the configuration natively. | This proves the default path remains usable without snapshotting its values. |
| Notarius | Default `v0.6.0` and commit verification | Present default release identity | Remove | Delete fixed `default_commit` and exact default-version assertions. | These fail solely when the supported default advances. |
| Notarius | Source, binary, and configuration metadata | Trusted module postconditions | Remove | Delete ownership, mode, and regular-file assertions. | They re-test `git`, `file`, and `template`. |
| Notarius | Exact minimal default document `{"version": 4}` | Current default rendering | Remove | Do not snapshot the default document. Supply `notarius_config_version` explicitly in the representative case and make any omission assertions about explicitly null inputs. | This preserves schema-bound behavior without turning future defaults into failures. |
| Notarius | Native version command and configuration validation | Installed CLI is usable and accepts the managed configuration | Retain | Keep both native interfaces, but assert an exact version only in the explicitly selected release scenario. | These are application-level outcomes. |
| Notarius | Baseline immediate repeat | Clean convergence | Retain | Keep one overall clean repeat. | This directly enforces the idempotence requirement. |
| Notarius | Missing binary | The required output is rebuilt and then converges | Simplify | Retain artifact removal, native CLI verification, and the following clean repeat; remove task greps. | Missing-output recovery is role logic needed around the imperative build. |
| Notarius | Dependency opt-out and custom Go executable | The caller-selected build executable is honored | Simplify | Keep wrapper invocation evidence and combine with missing-binary recovery; remove task greps and redundant repetitions. | This is meaningful configurable behavior with no better final-state discriminator. |
| Notarius | Binary metadata repair | Built-in file convergence | Remove | Delete the complete scenario. | It tests trusted module behavior. |
| Notarius | Explicit `v0.5.0` selection | A caller-selected immutable tag becomes the installed application | Simplify | Retain `notarius_version: v0.5.0` and exact native output `notarius v0.5.0`; remove expected commit and task-state assertions. | This remains useful after the role's default changes. |
| Notarius | Restore `v0.6.0` default | Cleanup and present default identity | Simplify | Reduce to cleanup only. | It is not a distinct stable behavioral test. |
| Notarius | Representative configuration | Field mapping, nested sections, pipelines, and validity | Simplify | Use a smaller set of explicit values and assert only those paths plus specifically selected null omissions; retain native validation. | Exact equality for a large complete document is broader and more brittle than the behavior requires. |
| Notarius | Separate `profile_dir` case | One simple optional leaf mapping | Remove | Do not maintain a standalone scenario; a future representative case may select one profile source if it adds value. | The direct conditional and serialization are self-evident and already represented by other optional fields. |
| Notarius | Separate `profile_file` case | A second simple optional leaf mapping | Remove | Delete the standalone scenario. | It duplicates the shape and risk of the profile-directory case without protecting a distinct likely regression. |
| Notarius | Explicit falsey values | Zero, false, empty mapping, and empty string survive rendering | Retain | Fold representative falsey values into the focused configuration scenario and assert only those paths. | Null-versus-falsey behavior is a deliberate role invariant. |
| Notarius | Caller-side pipeline composition | Independently defined mappings can be combined and passed through intact | Retain | Keep composition through ordinary `combine`, assert the two resulting pipeline entries, and run native validation; fold it into the representative configuration scenario if clarity permits. | This is an expressly selected public boundary and a plausible integration regression. |
| Notarius | Configuration task changed while build task skipped | Configuration changes without rebuilding | Remove | Delete `require_configuration_change_without_build` and all task-trace greps. Verify final configuration, CLI usability, and clean repeat instead. | Task execution is not a stable public interface. |
| Notarius | Restore the minimal default configuration | Cleanup plus mutable default assertions | Simplify | Keep cleanup only; remove exact default document, version, commit, task-state, and extra repeat checks. | The behavioral assertions duplicate change detectors elsewhere. |
| Notarius | Platform failure matrix | Straightforward platform assertions | Remove | Delete the matrix and `tests/unsupported.yml`. | It provides no proportionate role-specific value. |
| Notarius | Final commit, metadata, version, and config checks | Duplicate assertions | Remove | Delete them. | They repeat earlier verification and freeze the current default. |
| Notarius | `tests/verify.yml` broad installation contract | Commit, metadata, default document, version, and validity | Replace | Reduce to native CLI smoke and configuration validation, with exact version verification only for an explicit tag. | This retains application outcomes while removing module tests and mutable snapshots. |
| Notarius | README validation claims | Description of the current broad suite | Replace | Rewrite after simplification to describe the retained behavior. | Documentation should match the lean suite rather than preserve obsolete coverage promises. |
## Proposed Lean Target Suites
### Seriatim
1. Install pinned collections, syntax-check the convergence play, and lint the
role and retained test files.
2. Apply the role with defaults as a smoke test and immediately require a clean
repeat, without asserting the current default tag or commit.
3. Select `v1.4.0` explicitly and verify native output
`seriatim version v1.4.0`.
4. Delete the binary, supply a wrapper through `seriatim_go_binary` with
dependency management disabled, converge, verify that the wrapper was used
and the installed CLI works, then require a clean repeat.
5. Restore defaults as cleanup without treating the restored value as a test
expectation.
### Audita
1. Install pinned collections, syntax-check the convergence play, and lint the
role and retained test files.
2. Apply the role with defaults, validate the managed configuration with
Audita, and immediately require a clean repeat. Do not assert the complete
default document or current source identity.
3. Apply one representative explicit configuration spanning nested, list,
scalar, duration, falsey, and explicit-null behavior. Assert only the
selected paths and omissions, validate it with Audita, and require a clean
repeat.
4. Delete the binary, supply a logging wrapper through `audita_go_binary` with
dependency management disabled, converge, verify wrapper use and CLI
usability, then require a clean repeat.
5. Omit version-selection coverage until Audita exposes a native release
identity; do not substitute a raw-commit checkout test.
6. Restore defaults as cleanup only.
### Notarius
1. Install pinned collections, syntax-check the convergence play, and lint the
role and retained test files.
2. Apply the role with defaults, exercise `notarius --version`, validate the
managed configuration, and immediately require a clean repeat without
asserting the current default values.
3. Select `v0.5.0` explicitly and verify native output `notarius v0.5.0`.
4. Delete the binary, supply a logging wrapper through `notarius_go_binary`
with dependency management disabled, converge, verify wrapper use and CLI
usability, then require a clean repeat.
5. Apply one representative explicit configuration that includes selected
nested values, explicit falsey and null values, and two caller-composed
pipeline mappings. Assert only those behaviors, validate the file with
Notarius, and require a clean repeat.
6. Restore defaults as cleanup only.
## Documentation Follow-up
The README validation sections in all three role repositories should be
rewritten with their test harnesses. They currently advertise current-default,
metadata, task-arrangement, and platform-guard coverage recommended for
removal.
The durable feature roadmaps may continue to record the selected default tags,
paths, ownership, permissions, and platform support as feature requirements.
Those requirements need not each have a dedicated integration assertion.
Test-specific roadmap language should, however, be corrected as follows:
- Feature 0001 and Feature 0003 should describe exact native version checks as
checks of an explicitly selected immutable tag, not the current default.
- Feature 0002 currently says repository-local tests execute Audita to verify
its installed version. That is not implementable with Audita's current CLI
and should be replaced with the limitation and follow-up described above.
- Platform support remains part of each role contract, but the roadmaps should
not imply that each straightforward assertion requires a negative matrix.
## Recommended Remediation Order
1. Simplify the Seriatim driver and verifier, remove its unsupported-platform
playbook, and update its README.
2. Simplify Audita's driver and verifiers, consolidate its configuration case,
remove its unsupported-platform playbook, and update its README.
3. Simplify Notarius's driver and verifiers, consolidate configuration and
pipeline coverage, remove its unsupported-platform playbook, and update its
README.
4. Correct the test-specific language in the three feature roadmaps.
5. Run all three complete integration entry points and confirm every role
repository remains clean after its cleanup path.
No shared test abstraction is recommended. The three shell drivers have
similar mechanics, but keeping each suite local and readable is worth the
small amount of duplication, and a shared helper would create cross-repository
coupling for little present benefit.
## Audit Completion
Every materially distinct implemented scenario has been classified above. The
recommended removals either duplicate retained application-level coverage or
exercise behavior owned by trusted Ansible modules or straightforward
assertions. The lean targets retain default smoke coverage, immediate clean
convergence, imperative missing-output recovery, caller-supplied build tooling,
explicit release selection where natively observable, and representative
configuration behavior.
The audit made no changes to production roles or test implementations.
## Remediation Status
The recommended remediation was implemented and independently reviewed. No
production role behavior changed. The role commits are:
| Repository | Remediation commit | Final integration result |
| --- | --- | --- |
| `ansible-role-seriatim` | `e08c63c` | Pass |
| `ansible-role-audita` | `d2d0b9d` | Pass |
| `ansible-role-notarius` | `cfecf37` | Pass |
Final sequential validation on the approved Ubuntu 26.04 `x86_64` proxy ran
each repository's `tests/integration` entry point successfully. Each cleanup
path restored the default deployment, and the role repositories were clean
after their remediation commits. The existing classifications remain the
authoritative rationale for this implemented suite shape.
Independent review found no remaining code-quality issues or implementation
gaps. The three complete integration entry points passed again sequentially;
Bash syntax validation and `git diff --check` passed; native application checks
confirmed that cleanup restored usable default deployments; and every
repository in the workspace remained clean. No additional remediation record
was required.

View File

@@ -0,0 +1,192 @@
# Test Suite Audit Plan
Status: complete
## Objective
Audit the implemented integration tests for the three completed standalone
roles against the workspace's classical, state-based testing policy. The audit
will identify tests that protect stable role-owned behavior, tests that should
be simplified or replaced, and tests whose maintenance cost exceeds their
value.
This is a review plan, not authorization to change role code or test suites.
Any proposed remediation will be reviewed before a separate implementation
plan is prepared.
## Scope
The audit covers the test harnesses, playbooks, fixtures, inventories, and
test-related documentation in:
- `ansible-role-seriatim`
- `ansible-role-audita`
- `ansible-role-notarius`
Production role tasks, defaults, templates, and metadata may be inspected when
needed to determine whether a test protects public role behavior or merely
repeats an implementation detail. They are not remediation targets during the
audit.
The audit does not cover the proof-of-concept `rakestraw-ansible` role, the
suite-level role, or the collection. Those projects do not form part of the
three completed standalone-role test suites.
## Governing Standard
Apply the normative testing house style in `docs/testing.md`. In
particular, the audit will favor tests that exercise the role through its
public variables and inspect meaningful final application behavior. It will
disfavor tests that:
- freeze current defaults or other intentionally changeable values;
- assert task names, order, individual task status, or other execution traces;
- independently re-prove the documented postconditions of trusted Ansible
modules;
- exhaustively exercise self-evident assertions or equivalent low-value
combinations; or
- duplicate another test without protecting a distinct requirement or
plausible regression.
An immediate second convergence with no reported changes remains required for
each role. An explicitly selected version may be verified through the
application's native interface; the role's current default version may not be
treated as a permanent expected value.
## Classification Rubric
Classify every behavioral test case, including each materially distinct case
embedded in a shared playbook or shell harness, as one of the following:
- **Retain:** protects stable, role-owned behavior through an externally
meaningful outcome.
- **Simplify:** protects useful behavior but includes redundant assertions,
duplicated setup, or implementation coupling that can be removed.
- **Replace:** addresses a valid requirement through an unstable or indirect
assertion and should be expressed as a state-based outcome instead.
- **Remove:** tests a mutable default, trusted module behavior, an
implementation trace, or behavior without a stated requirement or plausible
regression.
- **Add:** identifies a material role-owned behavior that currently lacks
representative coverage.
Each classification must state the behavior at issue and the reason for the
recommended action. File length, test count, and aesthetic preference are not
sufficient reasons by themselves.
## Audit Record
Write the completed review to
`docs/roadmap/test-suite-audit-findings.md`. Record each finding in a table with
these fields:
| Repository | Test or case | Behavior protected | Classification | Recommended action | Rationale |
| --- | --- | --- | --- | --- | --- |
The report must also provide a proposed lean target suite for each role and
identify any shared harness behavior that should be made consistent across the
three repositories. Recommendations to remove coverage must state whether the
behavior remains covered elsewhere or why it does not warrant coverage.
## Stage 1: Establish the Baseline
1. Confirm that the workspace and all three role repositories begin clean.
2. Inventory every test entry point, playbook, fixture, inventory, helper, and
test-related README statement in scope.
3. Run each existing integration entry point without modification:
```text
(cd ansible-role-seriatim && tests/integration)
(cd ansible-role-audita && tests/integration)
(cd ansible-role-notarius && tests/integration)
```
4. Record success or failure, the scenarios exercised, and any environmental
assumptions needed to reproduce the result. A pre-existing failure is audit
evidence, not permission to repair it during this stage.
Completion criterion: the report contains a reproducible baseline and a
complete test inventory for all three roles.
## Stage 2: Audit Seriatim
1. Map every Seriatim test case to a documented public behavior or classify it
as lacking one.
2. Review version selection, caller-supplied build tooling, rebuild behavior,
metadata handling, platform validation, and repeat convergence using the
common rubric.
3. Identify assertions that inspect Ansible execution details or separately
verify state already owned by trusted modules.
4. Propose the smallest representative Seriatim suite that preserves valuable
regression protection.
Completion criterion: every Seriatim case is classified and the report states
the proposed retained, revised, removed, and missing coverage.
## Stage 3: Audit Audita
1. Map every Audita test case to a documented public behavior or classify it
as lacking one.
2. Review explicit version selection, native application verification,
configuration rendering, omission of null settings, preservation of falsey
values, platform validation, and repeat convergence.
3. Distinguish tests of the role's configuration decisions from tests that
merely repeat `template`, `file`, `git`, or package-module guarantees.
4. Propose the smallest representative Audita suite that preserves valuable
regression protection.
Completion criterion: every Audita case is classified and the report states
the proposed retained, revised, removed, and missing coverage.
## Stage 4: Audit Notarius
1. Map every Notarius test case to a documented public behavior or classify it
as lacking one.
2. Review explicit version selection, native application verification,
optional configuration rendering, falsey values, caller-composed pipeline
mappings, platform validation, and repeat convergence.
3. Distinguish tests of role-authored mapping and rendering behavior from
assertions about trusted module mechanics or the current implementation
layout.
4. Propose the smallest representative Notarius suite that preserves valuable
regression protection.
Completion criterion: every Notarius case is classified and the report states
the proposed retained, revised, removed, and missing coverage.
## Stage 5: Reconcile the Three Suites
1. Compare classifications across roles so equivalent patterns receive
equivalent treatment, while preserving genuine application differences.
2. Identify duplicated harness machinery, inconsistent terminology, and
documentation that describes implementation details or mutable defaults as
promised test behavior.
3. Separate static validation such as syntax checking and linting from
behavioral integration coverage.
4. Produce a repository-by-repository remediation proposal ordered by value
and dependency. Do not propose a shared abstraction unless it removes
demonstrated duplication without obscuring the individual role suites.
5. Confirm that the proposed target for every role still includes a default or
representative convergence, an immediate clean second convergence, and
focused coverage of each retained role-owned behavior.
Completion criterion: the findings report is internally consistent, gives a
lean target suite for each repository, and contains enough detail to support a
later implementation plan without leaving test-policy decisions to the
executor.
## Audit Completion Criteria
The audit is complete when:
- every implemented behavioral case across all three repositories has an
explicit classification and rationale;
- baseline results and reproduction commands are recorded;
- proposed removals do not silently discard coverage of a required public
behavior;
- proposed additions are limited to material role-owned behavior;
- README and harness-documentation corrections are identified alongside test
changes;
- no production or test implementation has been changed during the audit; and
- the findings have been reviewed before any remediation plan is written to
`docs/roadmap/implementation.md`.

View File

@@ -1,10 +1,18 @@
# Workspace Status # Workspace Status
Last updated: 2026-09-07 Last updated: 2026-09-29
Current milestone: MVP design and workspace foundation Current milestone: Operational D&D pipeline deployment
Current focus: Select the next open design topic before role implementation. Current focus: Feature 0023 is complete after independent review with no findings.
Narratio v3.1.0 and Scriptorium credential selection are wired through the
standalone role, D&D suite, collection, and local consumer pins. No active
implementation plan remains. Deployment of this update and live credential
validation remain operator activities; neither was performed by this feature.
Feature 0022 and the application upgrade sequence remain complete. Broader
downgrade/removal policy remains unselected design work.
See the [upgrade sequence](roadmap/application-upgrade-sequence.md) and
[feature evidence](roadmap/features/0023-narratio-scriptorium-credentials.md).
| ID | Deliverable | Owner | State | Evidence or next step | | ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
@@ -13,10 +21,35 @@ Current focus: Select the next open design topic before role implementation.
| M0-03 | Tracked MVP roadmap | workspace | done | `docs/roadmap/mvp.md` established | | M0-03 | Tracked MVP roadmap | workspace | done | `docs/roadmap/mvp.md` established |
| M0-04 | Aggregate repository status | workspace | done | `scripts/status` created | | M0-04 | Aggregate repository status | workspace | done | `scripts/status` created |
| M0-05 | Suite-level role repository | ansible-role-dnd-pipeline | done | Repository created and added to `workspace.yml` | | 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 | ready | Select the next item from the roadmap | | M1-01 | Remaining MVP design decisions | workspace | done | Feature 0003 roadmap fixes the Notarius configuration interface |
| M1-02 | Standalone application roles | role repositories | proposed | Begin after relevant interfaces are settled | | 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 | proposed | Begin after standalone role interfaces stabilize | | M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | done | Features 0006 through 0011 completed through remediation commit `de1b191` |
| M1-04 | Collection assembly | ansible-collection-dnd | proposed | Select and implement the pipeline-role incorporation mechanism | | M1-04 | Collection assembly | ansible-collection-dnd | done | Implemented and independently reviewed through collection remediation commit `da67b34` |
| 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 |
| F0003 | Install and configure Notarius | ansible-role-notarius | done | Implemented and validated through remediation commit `eb4f511` |
| F0004 | Install and configure Scriptorium | ansible-role-scriptorium | done | Implemented and validated through remediation commit `8f47aa8` |
| F0005 | Install and configure Narratio | ansible-role-narratio | done | Implemented and validated through remediation commit `7feff47` |
| 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 | done | Implemented and independently reviewed through remediation commit `b15fe8d` |
| F0010 | Integrate D&D Notarius extraction | ansible-role-notarius and ansible-role-dnd-pipeline | done | Implemented and independently reviewed through remediation commit `bbf01e1` |
| F0011 | Deliver pipeline credentials and Notarius reuse | ansible-role-narratio and ansible-role-dnd-pipeline | done | Implemented and independently reviewed through remediation commit `de1b191` |
| F0012 | Assemble the D&D collection | ansible-collection-dnd and ansible-role-dnd-pipeline | done | Pipeline `600eb21` assembled and validated through collection remediation commit `da67b34` |
| F0013 | Publish the first coordinated suite release | all Ansible repositories and workspace | done | Public [`rakestraw.dnd` 0.1.0 release](https://gitea.maximumdirect.net/eric/ansible-collection-dnd/releases/tag/v0.1.0); documentation remediation completed in pipeline `78afffe` and collection `5e695f3` |
| F0014 | Enroll existing pipeline operators | ansible-role-dnd-pipeline, ansible-collection-dnd, and workspace | done | Pipeline `c13f726` and collection import `c0b0ebd` passed their complete integration suites and independent review with no remediation findings |
| F0015 | Enable D&D S3 storage and publishing | ansible-role-dnd-pipeline, ansible-collection-dnd, and workspace | done | Pipeline `51566afcf69083cdbb5b5718f2544c86b079001c`, collection fixture `cf3de016ee09edf91afc3bc1addfd926d4a172ad`, collection squash `77f67adbc0f700e88bc15554e02052eaa22f1033`, and collection merge `46913446765e86ecfb29ebad9955d579ef6a4c7e` passed the complete repository suites and independent review with no remediation findings |
| F0016 | Prepare the D&D deployment playbook for `pipeline-dnd` | rakestraw-ansible and workspace | done | Consumer `716a80e`, `12b2462`, and `7f8353d` passed independent review with no findings; public dependency installation, target-only host listing, syntax and whitespace checks passed. Follow-up `7f4c90a` pins collection `2a53979` for Narratio v2.1.2; collection build and syntax checks passed |
| F0017 | Compose the Notarius testing overlay | Narratio role, pipeline role, collection, consumer, and workspace | done | Published through Narratio `330afe7`, Notarius `a82a83d`, pipeline `c56a942`, collection `ce5b838`, and consumer `0ced48c`; independent review found no remediation issues; validation evidence is in the feature roadmap |
| F0018 | Adopt Scriptorium v0.15.0 | Scriptorium role and workspace | done | Role commits `61dcafe`, `2fce529`, and `b174c8c` passed independent review with no findings; feature roadmap records validation; suite pins unchanged |
| F0019 | Adopt Audita v2.0.1 | Audita role and workspace | done | Role `c3dd59f`, following `6137ff2` and `52f67fe`, passed independent review with no findings; [roadmap](roadmap/features/0019-audita-v2-adoption.md) records validation; suite pins unchanged |
| F0020 | Adopt Notarius v0.8.1 | Notarius role and workspace | done | Role `6aef48b`, following `b1b922c` and `380b6a3`, passed independent review with no findings; [feature roadmap](roadmap/features/0020-notarius-v0-8-adoption.md) records evidence; suite pins unchanged |
| F0021 | Adopt Narratio v3.0.0 | Narratio role and workspace | done | Role `3c0700b`, following `a28f22c` and `45f6836`, passed independent review with no findings; [feature roadmap](roadmap/features/0021-narratio-v3-adoption.md) records evidence; suite pins unchanged |
| F0022 | Integrate the reviewed application upgrades | Pipeline role, collection, consumer, and workspace | done | Closed after review and resolution of all three findings; public pipeline `37b1cf6`, public collection `b3bc045`, local consumer `15f0f4e`; [remediation evidence](roadmap/remediation.md) |
| A0001 | Audit completed standalone-role test suites | workspace and standalone roles | done | Findings recorded in `docs/roadmap/test-suite-audit-findings.md` |
| F0023 | Adopt Narratio v3.1.0 and forward Scriptorium credentials | Narratio role, pipeline role, collection, consumer, and workspace | done | Public Narratio role `758aed7a`, pipeline `0f841fd`, collection `002e86c`; local consumer `67cc22f`. Independent review found no actionable issues; [feature evidence](roadmap/features/0023-narratio-scriptorium-credentials.md) |
| R0001 | Simplify completed standalone-role test suites | workspace and standalone roles | done | Role commits `e08c63c`, `d2d0b9d`, and `cfecf37` passed implementation and independent review |
## Updating This File ## Updating This File

47
docs/testing.md Normal file
View File

@@ -0,0 +1,47 @@
# Testing House Style
This policy is normative for creating, changing, reviewing, and auditing tests
in this workspace.
- Use a classical state-based approach, also commonly described as Chicago or
Detroit style. Exercise the real role through its public interface and
observe the resulting deployed system.
- Test behavior owned by the role, not the current arrangement of tasks that
implements it. A useful test should normally remain valid after an internal
refactor that preserves the same public behavior.
- Require an immediate second role application to report no changes. Clean
repeated convergence is a first-class role outcome, not a test of any one
module.
- Distinguish configurable behavior from current defaults. To prove version
selection, explicitly request a version and verify that the application
reports that version. Do not assert that the same version remains the role's
default. For example, a useful test sets `audita_version: v0.9.0` and verifies
that the installed Audita reports `v0.9.0`; a harmful test asserts that
`v0.9.0` is the role's current default. The former continues to prove version
selection after the default advances to `v0.10.0`, while the latter fails
merely because of the intended update.
- Use a default invocation as a smoke test when useful, but do not snapshot
exact default values, selected commits, complete default configuration
documents, or counts of default variables. Those assertions are change
detectors that turn intentional updates into unrelated test failures.
- Do not assert task names, task order, individual `changed` or `skipped`
results, or other implementation traces. Inspect the final system and the
overall clean-repeat result instead.
- Do not test documented behavior of `ansible.builtin`, widely used
`community.general`, or other trusted modules. In particular, do not
independently verify file existence, ownership, permissions, package state,
checkout state, or template deployment merely to repeat module arguments.
- Test role-authored decisions only when they express meaningful public
behavior. Examples include an explicitly selected application version, a
caller-supplied build executable, configuration rendering with representative
non-null and falsey values, and composition of caller-supplied mappings.
- Verify application outcomes with the application's native interface when
practical. Prefer executing the installed application or its configuration
validator over reconstructing its rules in Ansible assertions.
- Self-evident declarative guards, including straightforward platform
assertions, do not require a negative test matrix.
- Prefer one representative case for a behavior over exhaustive combinations.
Every additional test must protect a requirement or a plausible regression,
not merely increase coverage.
- Keep syntax checking and linting as static validation. They complement the
behavioral suite but do not justify tests that freeze implementation details.

31
requirements-dev.txt Normal file
View File

@@ -0,0 +1,31 @@
# Fully resolved workspace development toolchain for Python 3.14 on Ubuntu
# 26.04. Regenerate deliberately when upgrading ansible-core or ansible-lint.
ansible-compat==26.8.0
ansible-core==2.21.3
ansible-lint==26.8.0
attrs==26.1.0
black==26.5.1
bracex==3.0.1
cffi==2.1.1
click==8.5.0
cryptography==50.0.1
distro==1.9.0
filelock==3.32.5
Jinja2==3.1.6
jsonschema==4.26.0
jsonschema-specifications==2025.9.1
MarkupSafe==3.0.3
mypy_extensions==1.1.0
packaging==26.3
pathspec==1.1.1
platformdirs==4.11.7
pycparser==3.0
pytokens==0.4.1
PyYAML==6.0.3
referencing==0.37.0
resolvelib==1.2.1
rpds-py==2026.6.3
ruamel.yaml==0.19.1
subprocess-tee==0.4.2
wcmatch==11.0.1
yamllint==1.38.0

View File

@@ -51,6 +51,18 @@ repositories:
category: reference category: reference
purpose: Existing deployment repository and pipeline_dnd proof of concept purpose: Existing deployment repository and pipeline_dnd proof of concept
- name: campaigns
path: assets/campaigns
remote: https://gitea.maximumdirect.net/eric/campaigns.git
category: content
purpose: D&D campaign registry content deployed by the pipeline role
- name: narratio-prompts
path: assets/narratio-prompts
remote: https://gitea.maximumdirect.net/eric/narratio-prompts.git
category: content
purpose: PromptKit-compatible prompts and schemas deployed for Scriptorium
- name: narratio - name: narratio
path: ../narratio path: ../narratio
remote: https://gitea.maximumdirect.net/eric/narratio.git remote: https://gitea.maximumdirect.net/eric/narratio.git
@@ -80,9 +92,3 @@ repositories:
remote: https://gitea.maximumdirect.net/eric/scriptorium.git remote: https://gitea.maximumdirect.net/eric/scriptorium.git
category: application category: application
purpose: Scriptorium source and authoritative application contracts purpose: Scriptorium source and authoritative application contracts
- name: narratio-prompts
path: ../narratio-prompts
remote: https://gitea.maximumdirect.net/eric/narratio-prompts.git
category: content
purpose: PromptKit-compatible pipeline prompt library