Files
ansible-workspace-dnd/docs/roadmap/mvp.md

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