Plan the Scriptorium role implementation

This commit is contained in:
2026-09-09 14:20:26 +00:00
parent 77dcf8f7f7
commit bbeecc0055
3 changed files with 709 additions and 10 deletions

View File

@@ -0,0 +1,331 @@
# Feature 0004: Scriptorium Source Installation and Configuration
Status: ready
## 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.
After this feature, 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.
## 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

@@ -1,11 +1,377 @@
# Implementation Plan
# Implementation Plan 0004: Install and Configure Scriptorium
Status: pending
Status: ready
No implementation plan is currently active. Test-suite remediation R0001 was
implemented in role commits `e08c63c`, `d2d0b9d`, and `cfecf37`, then reviewed
successfully. Its rationale and validation record remain in
[the test-suite audit findings](test-suite-audit-findings.md).
Target executor: GPT-5.6-Terra
Select and approve the next unit of work before replacing this notice with a
new staged implementation plan.
Feature roadmap:
[Feature 0004: Scriptorium Source Installation and Configuration](features/0004-scriptorium-source-installation-and-configuration.md)
Active plan location: `docs/roadmap/implementation.md`
## Objective
Implement the small, independently usable `rakestraw.scriptorium` role defined
by Feature 0004. Install Scriptorium from its pinned source release, build its
executable on the managed host, and manage its YAML configuration through the
approved nullable field-specific interface without adding D&D-specific
content or service management.
The feature roadmap remains authoritative for scope, rationale, target end
state, public variables, and acceptance criteria.
## Execution Rules
- Execute Stage 1 and Stage 2 in numeric order.
- Immediately before each stage, read every document in that stage's Required
Policy Review, then confirm its preconditions and the owning repository's
working-tree state.
- Modify only `ansible-role-scriptorium`. Treat this workspace,
`../scriptorium`, `rakestraw-ansible`, and every other repository as
read-only during out-of-band implementation.
- Preserve unrelated changes. Stop if the role repository is unexpectedly
dirty at a stage boundary.
- Implement the feature roadmap's nine-operation module-driven flow. Trust
APT, Snap, `file`, `git`, and `template` to inspect and converge the state
they own.
- Inspect only whether the binary exists because that result is independently
required to decide whether the imperative build command must run.
- Put checkout change and binary absence directly on the build task. Do not
introduce another fact, handler, fingerprint, checksum, manifest, or
role-private state.
- Do not execute Scriptorium from production role tasks. Native verification
belongs only in the integration suite.
- Render configuration with one template task. Use `is not none`, omit empty
parent sections, preserve falsey non-null values, and serialize values with
filters rather than manual YAML quoting.
- Accept `scriptorium_backends` as one caller-supplied native mapping. Do not
define its arbitrary backend IDs as role variables or implement role-side
file loading, merging, or precedence.
- Exercise the role through public variables and native application outcomes.
Do not assert current default values, task traces, or state already
guaranteed by trusted modules.
- Use fully qualified collection names and `argv` for command execution.
- Run each stage's validation before committing it. Do not begin Stage 2 if
Stage 1 fails validation.
- Commit each completed stage with its specified plain-English message. Do not
push.
- Treat `/usr/local/src/scriptorium`, `/usr/local/bin/scriptorium`, and
`/usr/local/etc/scriptorium/config.yml` as disposable role-managed test
state. Restore the default role deployment through test cleanup.
## Starting State and Preconditions
- `ansible-role-scriptorium` is clean on `main` at
`2cd69a4b2ead23b44f1aab51fd1b1f14ac326af2`, tracking `origin/main` without
divergence.
- This plan and the ready Feature 0004 roadmap are committed before
out-of-band execution begins.
- The Scriptorium managed source, binary, and configuration paths are absent
before initial execution and contain no user data that must be preserved.
- The local controller and managed-host proxy are Ubuntu 26.04 `x86_64`, with
gathered facts and passwordless privilege escalation available.
- Workspace tooling is available in `../.venv/bin` from the role repository:
Ansible Core 2.21.3 and ansible-lint 26.8.0.
- `community.general` 13.3.0 and Go Snap channel `1.26/stable` are available.
- Upstream annotated tag `v0.13.0` resolves to
`f33af205242cbaeeb689c179c0465bd10beaa1a3` and declares Go 1.25.5.
- The native build uses package `./cmd/scriptorium`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flags `-s -w`.
- Scriptorium accepts an empty YAML mapping as application configuration and
supplies built-in defaults for every omitted field.
- `scriptorium inspect profile` is an offline native command that can exercise
configuration loading with a test-owned endpoint profile without making a
model request.
- Scriptorium does not expose native application release identity. The plan
deliberately omits a version-selection test rather than inspecting the Git
checkout or snapshotting release-specific behavior.
## Repository Scope
Repository that changes:
- `ansible-role-scriptorium`: role implementation, public interface,
configuration template, metadata, dependency declaration, README, and
repository-local integration suite.
Repositories that may be inspected but must remain unchanged:
- `ansible-workspace-dnd`: authoritative roadmap, plan, policies, and status.
- `../scriptorium`: authoritative release, build, CLI, and configuration
contracts.
- `rakestraw-ansible`: historical style and deployment reference.
- Every other repository in `workspace.yml`.
## Stage 1: Implement the Complete Minimal Role
### Objective
Create a complete standalone role that installs and configures Scriptorium
with the fixed public interface, concise production task flow, minimal
configuration template, documentation, and baseline idempotence coverage.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
### Preconditions
- The starting revisions and upstream contracts above remain unchanged.
- `ansible-role-scriptorium` has no uncommitted changes.
- The workspace planning commit containing this plan exists.
- The three managed Scriptorium paths contain no data that must be preserved.
### Owning Repository
`ansible-role-scriptorium`
### Required Changes
1. Retain the existing license and add the conventional role structure:
`defaults/main.yml`, `meta/main.yml`, `meta/argument_specs.yml`,
`tasks/main.yml`, `templates/config.yml.j2`,
`collections/requirements.yml`, `ansible.cfg`, and focused files under
`tests/`.
2. Declare role name `scriptorium`, namespace `rakestraw`, author Eric
Rakestraw, license `CC0-1.0`, Ubuntu 26.04 support, Ansible Core 2.18 or
newer, an empty dependency list, and the repository's canonical issue
tracker. Pin `community.general` to `13.3.0`.
3. Define the eight installation variables and ten nullable configuration
variables in the Feature 0004 Fixed Public Interface. Mirror their public
names and native shapes in `meta/argument_specs.yml`:
- use `path` for source, binary, Go executable, configuration, and the three
application directory variables;
- use `bool` for dependency management;
- use `int` for the three server byte limits;
- use `dict` for `scriptorium_backends`; and
- use `str` for the remaining variables.
Concrete installation defaults are required by the argument specification;
nullable application settings are optional. Do not reproduce Scriptorium's
semantic validation rules.
4. Implement one readable `tasks/main.yml` with this flow:
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 as
`root:root` mode `0755` with one `ansible.builtin.file` loop;
5. check out `scriptorium_version` with `ansible.builtin.git`,
`force: true`, and register its module result;
6. inspect only `scriptorium_binary_path` with `ansible.builtin.stat`;
7. build directly to `scriptorium_binary_path` when the checkout changed or
the binary is absent;
8. converge recursive `root:root` source ownership and binary `root:root`
mode `0755` with one item-driven `ansible.builtin.file` loop; and
9. render `templates/config.yml.j2` to `scriptorium_config_path` as
`root:root` mode `0644` with one `ansible.builtin.template` task.
5. Invoke `scriptorium_go_binary` with `ansible.builtin.command` and `argv`
from `scriptorium_source_dir`. Supply `build`, `-trimpath`, linker flags
`-s -w`, the configured output path, and package `./cmd/scriptorium`. Set
`CGO_ENABLED=0`, `GOWORK=off`, and `GOTOOLCHAIN=local`. Mark the executed
mutation changed as required for an imperative command.
6. Put
`scriptorium_checkout.changed or not scriptorium_binary.stat.exists`
directly on the build task. Register only the Git and binary results needed
by that expression.
7. Use task-level `become: true` for dependency installation and tasks that
manage root-owned state. Do not require play-level privilege escalation.
8. Make the template render `{}` when every configuration variable is null.
Otherwise conditionally emit the direct directory fields, `server`,
`defaults`, and `backends`. Emit `server` and `defaults` only when at least
one descendant is non-null. Serialize scalar values and the backend mapping
safely, and do not assemble a configuration dictionary in a fact.
9. Replace the placeholder README with concise documentation covering the
supported platform, fact and privilege requirements, every public variable,
dependency opt-out, build triggers, configuration discovery path,
null-as-omission behavior, falsey values, the native backend mapping,
caller-side composition, credential-name boundary, absent content/service
management, and actual integration-test effects.
10. Add a baseline integration harness with one `tests/integration` entry
point. Use strict shell options, repository-relative paths, a private
temporary directory, pinned collection installation, syntax checking,
production-profile ansible-lint, and a best-effort cleanup trap that
reapplies the default role and removes only its temporary directory.
11. In the baseline scenario, converge the default role without play-level
escalation. Create a private endpoint-profile fixture and exercise the
installed binary with an offline `scriptorium inspect profile` invocation
that explicitly loads the managed configuration. Successful native use is
sufficient; do not compare application output to a snapshot. Immediately
apply the same role again and require aggregate `changed=0` and `failed=0`.
12. Do not inspect source commits, ownership, permissions, package state, or
the exact default configuration in tests. Those are postconditions of the
modules that manage them, not additional role-authored behavior.
### Validation
From `ansible-role-scriptorium`, run:
```text
tests/integration
git diff --check
git status --short
```
Expected result: syntax and lint pass; the default role convergence succeeds;
Scriptorium accepts the managed configuration through an offline native
profile inspection; the immediate repeat reports `changed=0` and `failed=0`;
cleanup leaves a usable default deployment; and only intended Stage 1 files
are modified.
### Completion Criteria
- The fixed public interface is present in defaults and matching argument
specifications.
- Production tasks follow the nine-operation roadmap flow without additional
probes, private state, handlers, or production self-validation.
- The template expresses every native configuration field, renders `{}` by
default, omits null values and empty parents, and preserves non-null falsey
values.
- README, metadata, dependency declaration, task flow, template, and baseline
test description agree.
- Baseline native smoke testing and clean repeated convergence pass.
- No repository outside `ansible-role-scriptorium` changes.
### Commit
Commit intent: `Install and configure Scriptorium`
## Stage 2: Add Focused Behavioral Coverage
### Objective
Add representative coverage for missing-binary recovery through caller-owned
build tooling and for conditional configuration rendering through
Scriptorium's native offline interface.
### Required Policy Review
Before beginning this stage, read:
- `AGENTS.md`
- `docs/orientation.md`
- `docs/conventions.md`
- `docs/ansible.md`
- `docs/testing.md`
### Preconditions
- Stage 1 is committed and `ansible-role-scriptorium` is otherwise clean.
- Stage 1's complete integration entry point passes.
- The default managed deployment can be restored by applying the role with no
overrides.
### Owning Repository
`ansible-role-scriptorium`
### Required Changes
1. Retain the baseline default smoke and immediate clean repeat. Extend the
existing driver rather than introducing another integration framework or
shared cross-role test helper.
2. Add one recovery scenario that combines the two related public behaviors:
- create an executable temporary wrapper that records its invocation and
then delegates to `/snap/bin/go`;
- remove `/usr/local/bin/scriptorium`;
- apply the role with
`scriptorium_manage_build_dependencies: false` and
`scriptorium_go_binary` set to that wrapper;
- confirm the supplied executable was used;
- exercise the installed Scriptorium with the offline native smoke command;
and
- immediately repeat with the same inputs and require aggregate
`changed=0` and `failed=0`.
3. Add one representative configuration scenario. Supply a small selection
that spans direct and nested fields, including:
- a test-owned `scriptorium_profile_dir`;
- a non-default `scriptorium_server_addr`;
- at least one explicit zero server byte limit;
- `scriptorium_defaults_render_format: json`;
- selected null directory and server fields that must remain omitted; and
- one `scriptorium_backends` entry with an endpoint, zero capacity values,
and a false value inside `extra_params`.
4. Create a test-owned profile that selects the configured backend. Invoke
`scriptorium inspect profile` with the managed configuration and require
successful offline inspection without a provider request or credential
value.
5. Parse the rendered YAML and assert only representative role-authored
mappings: the selected direct and nested values are present, the selected
null fields are absent, zero and false values survive, and the selected
backend ID and definition are available. Do not compare the complete
document or verify file metadata.
6. Immediately repeat the representative convergence with the same explicit
variables and require aggregate `changed=0` and `failed=0`.
7. Keep the cleanup trap responsible for restoring the default deployment on
success or failure when possible. Test mutation is limited to the three
declared role-managed paths and the driver's private temporary directory.
8. Do not add an alternate-release scenario, checkout assertion, task-name
grep, change-count requirement for mutating runs, metadata-repair scenario,
unsupported-platform matrix, or exhaustive case for every variable.
9. Update the README validation section so it describes only the implemented
static checks, default smoke and clean repeat, combined recovery case, and
representative configuration case.
### Validation
From `ansible-role-scriptorium`, run:
```text
tests/integration
git diff --check
git status --short
```
Expected result: static validation and all three behavioral paths pass; the
specified repeat runs report `changed=0` and `failed=0`; the supplied Go
wrapper is observed during missing-binary recovery; native profile inspection
accepts and uses the representative configuration; cleanup restores a usable
default deployment; and only intended Stage 2 test and documentation changes
remain.
### Completion Criteria
- One recovery scenario proves both missing-binary rebuilding and use of the
caller-selected Go executable, followed by clean convergence.
- One representative configuration proves selected field mapping, null
omission, falsey-value preservation, backend pass-through, native acceptance,
and clean convergence.
- No test snapshots mutable defaults, inspects task traces, or rechecks
postconditions owned by trusted modules.
- The complete integration entry point passes and its README description is
accurate.
- No repository outside `ansible-role-scriptorium` changes.
### Commit
Commit intent: `Add focused Scriptorium integration coverage`
## Final Validation and Handoff
After Stage 2, from `ansible-role-scriptorium`, run:
```text
tests/integration
git log --oneline -2
git status --short --branch
cd ..
./scripts/status
```
Report both role commit hashes, the static and behavioral validation results,
the clean-repeat evidence, the restored default deployment, any deviation or
remaining concern, and any complexity beyond the planned task flow with the
acceptance criterion that required it.
Do not edit workspace planning files, mark Feature 0004 `done`, or push during
out-of-band implementation. Completion requires subsequent independent review.
## Progress Notes
No stages have been completed.

View File

@@ -4,7 +4,8 @@ Last updated: 2026-09-09
Current milestone: MVP standalone application roles
Current focus: Select the next unit of work.
Current focus: Execute the approved Feature 0004 Scriptorium implementation
plan.
| ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- |
@@ -14,12 +15,13 @@ Current focus: Select the next unit of work.
| 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` |
| M1-01 | Remaining MVP design decisions | workspace | done | Feature 0003 roadmap fixes the Notarius configuration interface |
| M1-02 | Standalone application roles | role repositories | in_progress | Select the next standalone application role feature |
| M1-02 | Standalone application roles | role repositories | in_progress | Implement Feature 0004 in `ansible-role-scriptorium` |
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | proposed | Begin after standalone role interfaces stabilize |
| M1-04 | Collection assembly | ansible-collection-dnd | proposed | Select and implement the pipeline-role incorporation mechanism |
| 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 | ready | Execute `docs/roadmap/implementation.md` |
| A0001 | Audit completed standalone-role test suites | workspace and standalone roles | done | Findings recorded in `docs/roadmap/test-suite-audit-findings.md` |
| R0001 | Simplify completed standalone-role test suites | workspace and standalone roles | done | Role commits `e08c63c`, `d2d0b9d`, and `cfecf37` passed implementation and independent review |