440 lines
24 KiB
Markdown
440 lines
24 KiB
Markdown
# Initial Roadmap
|
|
|
|
## Purpose
|
|
|
|
This document records the decisions that define the initial MVP of the
|
|
Narratio Ansible roles and D&D collection. It is the durable reference for
|
|
choices that have been settled while the suite is being designed. Open
|
|
questions and later ideas should remain clearly distinguished from these
|
|
locked decisions.
|
|
|
|
## MVP Goal
|
|
|
|
Build independently usable Ansible roles for the five Narratio applications
|
|
and compose them through a suite-level role developed in its own repository.
|
|
The `rakestraw.dnd` collection exposes that role as `rakestraw.dnd.pipeline`.
|
|
The suite-level role installs and configures the complete D&D transcript
|
|
processing pipeline on a single supported host. Operators or unattended
|
|
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.
|
|
|
|
## Locked Decisions
|
|
|
|
### Supported platform
|
|
|
|
- The MVP supports Ubuntu 26.04.
|
|
- The MVP supports both `amd64` and `arm64` hosts.
|
|
- The roles should be structured so support for additional distributions and
|
|
releases can be added after the MVP without redesigning them.
|
|
|
|
### Managed applications
|
|
|
|
The suite-level role installs and configures all five applications in the
|
|
Narratio suite:
|
|
|
|
- Narratio
|
|
- Notarius
|
|
- Audita
|
|
- Seriatim
|
|
- Scriptorium
|
|
|
|
WhisperX is an external HTTP service consumed by Narratio. Deploying or
|
|
managing the WhisperX service is outside the MVP scope, although the Narratio
|
|
role will manage the native configuration needed to connect to it.
|
|
|
|
### Application installation
|
|
|
|
- The MVP builds all five applications from their official Git repositories on
|
|
the target host. This consistent model avoids making the suite depend on
|
|
every upstream project publishing prebuilt artifacts.
|
|
- Released roles build an explicitly selected application release tag.
|
|
Development may override the selected revision with a branch or commit.
|
|
- Source checkouts reside at `/usr/local/src/<app>` and are owned by `root`.
|
|
- Roles build and install the binary at `/usr/local/bin/<app>` with
|
|
`root:root` ownership and mode `0755`, using the application's native build
|
|
command and the simplest clear Ansible task flow.
|
|
- Builds use the application repository's own build contract, including any
|
|
application-specific version-injection linker flags. The common baseline is
|
|
`GOWORK=off`, `GOTOOLCHAIN=local`, `CGO_ENABLED=0`, and `-trimpath`.
|
|
- Roles normally rebuild when the Git task reports a changed checkout or the
|
|
binary is absent. An application-level version or smoke check may add a
|
|
trigger only when its feature specification explicitly requires that
|
|
production behavior. Roles do not maintain fingerprints, checksums, or
|
|
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 is installed on the target host through the official Snap package using
|
|
classic confinement.
|
|
- The Snap channel is configurable and should track an explicit Go minor
|
|
release channel, rather than unconstrained `latest/stable`, when that channel
|
|
is available for the required Go version.
|
|
- The installed Go toolchain must satisfy the application's `go.mod`
|
|
requirement. Builds set `GOTOOLCHAIN=local` so provisioning does not silently
|
|
download a different toolchain.
|
|
- Each standalone application role can install its own build prerequisites and
|
|
exposes a variable allowing that behavior to be disabled. Repeating an
|
|
idempotent prerequisite task across the small roles is preferable to adding
|
|
a shared-role dependency during the MVP.
|
|
|
|
### Role and collection architecture
|
|
|
|
- All Ansible roles and collections in this suite use the root namespace
|
|
`rakestraw`.
|
|
- Each of the five managed applications has a separate, targeted Ansible role
|
|
in its own repository.
|
|
- Each application role owns installation and native configuration of that
|
|
application.
|
|
- The Narratio application role remains application-specific even though
|
|
Narratio is the runtime orchestrator for the full pipeline.
|
|
- The suite-level role is developed in the standalone
|
|
`ansible-role-dnd-pipeline` repository rather than directly in the collection
|
|
repository.
|
|
- The application and pipeline roles are independently developed, tested,
|
|
versioned, and released. An application-specific change therefore requires a
|
|
release of that application's role without requiring changes or releases in
|
|
unrelated role repositories.
|
|
- The collection is named `rakestraw.dnd`.
|
|
- The collection bundles and exposes the independently developed suite-level
|
|
role as `rakestraw.dnd.pipeline`, providing one opinionated interface for
|
|
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,
|
|
cross-application configuration, D&D campaign deployment, prompt-library
|
|
deployment, operator access, the pipeline-wide secret-delivery policy, and
|
|
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
|
|
dependencies. This is an intentional choice for the controlled project
|
|
environment despite the additional repository and dependency structure and
|
|
Ansible's preference for published collection dependencies.
|
|
- Consumer installation may require a dependency manifest or bootstrap step
|
|
that installs both the collection and its standalone role dependencies; a
|
|
plain collection installation is not assumed to resolve arbitrary Git role
|
|
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
|
|
the independently released applications while retaining a single opinionated
|
|
installation interface for the complete suite. It avoids forcing each small
|
|
role to become its own published collection and avoids coupling unrelated
|
|
application-role releases in one source repository.
|
|
|
|
### Ansible dependencies and task structure
|
|
|
|
- The standalone application roles are independently usable and prefer
|
|
`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
|
|
`maximumdirect.core.ansible_role_loader` role used by the proof of concept.
|
|
- Platform-specific task selection may be added later using ordinary Ansible
|
|
includes when another supported platform creates a concrete need.
|
|
- Small amounts of repeated prerequisite or installation logic are acceptable
|
|
during the MVP. A shared helper role or collection plugin should be
|
|
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
|
|
|
|
- Development dependency manifests may temporarily refer to branches or
|
|
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
|
|
to an immutable role release tag.
|
|
- The collection release is the compatibility record for the exact set of
|
|
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
|
|
combination delivered to consumers, starting from an environment in which
|
|
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
|
|
version in the collection, validating the assembled suite, and releasing a
|
|
new collection version. Unrelated application-role repositories remain
|
|
unchanged.
|
|
|
|
### Prompt library
|
|
|
|
- The pipeline role installs Narratio's PromptKit-compatible prompt library
|
|
from the `narratio-prompts` Git repository. The Scriptorium role owns its
|
|
native prompt and schema directory configuration, while the pipeline role
|
|
owns populating those locations with suite integration content.
|
|
- The upstream repository is
|
|
`https://gitea.maximumdirect.net/eric/narratio-prompts.git`.
|
|
- 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
|
|
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
|
|
|
|
- The standalone Narratio role creates a dedicated system `narratio` user and
|
|
`narratio` group. The account uses `/var/lib/narratio` as its default home
|
|
and has a non-login shell.
|
|
- The `narratio` account owns the suite's application configuration and
|
|
writable runtime directories; `narratio` is also the shared operator group.
|
|
- Application source trees and installed binaries are owned by `root` and are
|
|
not writable by operators or the runtime account.
|
|
- The supported operational model runs `narratio run` and other processing
|
|
commands either as the dedicated `narratio` account or as an existing human
|
|
account selected through the pipeline role's
|
|
`dnd_pipeline_operator_users` list. The list defaults to empty.
|
|
- Every selected human account must exist before pipeline convergence. The
|
|
role adds selected accounts to the runtime group with additive supplementary
|
|
membership and does not create accounts, replace other group memberships,
|
|
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
|
|
|
|
- Narratio is installed as a command-line application, not a persistent
|
|
daemon.
|
|
- Scheduling Narratio invocations through cron, systemd timers, or another
|
|
automation mechanism is not currently part of the locked MVP scope.
|
|
|
|
## Expected Filesystem Areas
|
|
|
|
The roles align with the applications' established default locations unless a
|
|
later design decision changes them:
|
|
|
|
- `/usr/local/etc/narratio` for Narratio configuration
|
|
- `/usr/local/etc/audita/config.yml` for Audita configuration
|
|
- `/usr/local/etc/notarius/config.yml` for Notarius configuration
|
|
- `/usr/local/etc/notarius/pipelines` for suite-owned imported Notarius
|
|
pipeline definitions
|
|
- `/usr/local/etc/scriptorium/config.yml` for Scriptorium configuration
|
|
- `/usr/local/etc/narratio/secrets` for suite-managed restricted credentials
|
|
- `/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/bin/<app>` for root-owned application binaries
|
|
- `/var/lib/narratio` for durable workspace and session state
|
|
- `/var/spool/narratio` for spool data
|
|
- `/var/cache/narratio` for cached data
|
|
- `/var/cache/notarius` for suite-provisioned Notarius chunk-plan and
|
|
checkpoint caches
|
|
|
|
The Narratio role creates and configures the campaign root; the pipeline role
|
|
populates it from the selected campaign source. `/usr/local/share` assumes Git
|
|
is authoritative and operators do not edit campaign content directly on the
|
|
managed host. The prompt-library checkout retains its upstream `prompts/` and
|
|
`schemas/` layout at the fixed root above.
|
|
|
|
## Deferred Beyond the MVP
|
|
|
|
- Linux distributions and Ubuntu releases other than Ubuntu 26.04
|
|
- Architectures other than `amd64` and `arm64`
|
|
- Installation from prebuilt application release artifacts
|
|
- Deploying or managing WhisperX
|
|
- Versioned Narratio prompt-library releases and pinning
|
|
- Versioned campaign-content releases and default release pinning
|
|
- 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
|
|
|
|
The following area requires investigation and decisions before implementation:
|
|
|
|
- Upgrade, downgrade, and removal behavior
|