Revise the Seriatim plan and workspace conventions

This commit is contained in:
2026-09-08 00:16:12 +00:00
parent aafee9ea62
commit fc803587b8
13 changed files with 479 additions and 895 deletions

102
AGENTS.md
View File

@@ -7,96 +7,14 @@ deploy the D&D transcript-processing pipeline. It owns cross-repository plans,
decisions, status, and workspace tooling. Each application and Ansible project
is an independent Git repository.
## Repository Map
## Required Reading
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.
- `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.
- `../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/roadmap/features/`: durable scope and target state for selected units
of work.
- `docs/status.md`: current cross-repository progress and next work.
- `docs/decisions/`: durable rationale for significant architectural choices.
- `docs/roadmap/implementation.md`: the single active staged implementation
plan, replaced for each selected feature after its feature roadmap is agreed.
- 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`.
- 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.
- 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.
- 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`. Add the same identifier to
`docs/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.
- Always write the current implementation plan to
`docs/roadmap/implementation.md`. Replace that file when planning the next
selected feature; Git history preserves prior plans when needed.
- 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
behavior, validation, completion criteria, and expected commit.
- Resolve architectural choices during roadmap and plan review. Do not leave
unresolved design judgment to the implementation agent.
- Update `docs/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 `docs/decisions/`.
- Use the status values `proposed`, `ready`, `in_progress`, `blocked`, `done`,
and `deferred`.
- Read [the workspace orientation](docs/orientation.md) before selecting,
inspecting, or modifying a repository. It maps the repositories and defines
the canonical sources of truth.
- Read [the workspace conventions](docs/conventions.md) before reviewing or
changing Ansible, preparing a feature roadmap or implementation plan, or
making any repository change. It defines the normative house style and
working conventions.
- Read [the planning policy](docs/planning.md) before preparing a feature
roadmap or implementation plan or managing an ongoing work stream.

49
docs/conventions.md Normal file
View File

@@ -0,0 +1,49 @@
# Workspace Conventions
## 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`.
- 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.
## Ansible House Style (Normative)
- 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.
- Trust the documented contract of each Ansible module, including its
idempotence and change detection.
- Gather state only when the result controls necessary behavior that the
responsible module cannot determine. Fingerprints, checksums, sidecar state,
manual drift detection, and speculative recovery paths require an explicit
acceptance criterion and rationale. Do not precede a declarative module with
a probe or recreate its internal logic unless a concrete requirement cannot
be expressed by the module itself.
- 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.

View File

@@ -0,0 +1,52 @@
# 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 a locally built executable is missing or has
the wrong application version.
- 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.

44
docs/orientation.md Normal file
View File

@@ -0,0 +1,44 @@
# 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.
- `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.
- `../narratio-prompts`: pipeline prompt-library content.
Use [the workspace inventory](../workspace.yml) as the complete
machine-readable inventory of paths and remotes.
## Sources of Truth
- [Workspace conventions](conventions.md): normative working and Ansible house
style.
- [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.
- Individual Ansible repositories: implementation and repository-local tests.

44
docs/planning.md Normal file
View File

@@ -0,0 +1,44 @@
# Planning and Progress
- Read and follow [the workspace conventions](conventions.md) before preparing
or revising any roadmap or implementation plan.
- 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
behavior, validation, completion criteria, and expected commit.
- 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,47 +1,49 @@
# Feature 0001: Seriatim Source Installation
Status: done
Status: ready
## Summary
Implement the first independently usable application role by teaching
`ansible-role-seriatim` to install Seriatim from a pinned upstream source
release. This feature establishes the source-build and role conventions that
can be reviewed before analogous work begins in the other application roles.
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 pipeline applications do not yet share a uniform prebuilt release model,
and the new Ansible role repositories contain only initial scaffolding. The MVP
therefore builds applications on the managed host. Seriatim is the smallest
useful proving ground because it has no central application configuration file,
allowing this feature to isolate installation, reproducibility, idempotence,
and validation concerns.
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
- Establish a conventional, independently usable Ansible role structure in
`ansible-role-seriatim`.
- 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 using classic confinement when build
- 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` and allow consumers to override
the channel or disable build-dependency management.
- Clone the official Seriatim repository into a root-owned managed source
directory, defaulting to `/usr/local/src/seriatim`.
- Default to the immutable `v1.5.0` release tag, verified as the latest current
upstream tag on 2026-09-07, while supporting explicit branch or commit
overrides for development.
- Build a native, statically linked Seriatim binary using the upstream build
contract, including release-version injection.
- Validate a staged binary before installing it as
`/usr/local/bin/seriatim` with `root:root` ownership and mode `0755`.
- Record sufficient build state to rebuild when the resolved source commit,
Go compiler version, or effective build arguments change.
- Validate the installed binary and demonstrate convergence on a repeated role
run.
- Document the role interface, defaults, supported platform, development
overrides, and validation procedure.
- 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, the binary is absent, or the
installed binary does not report the selected version.
- Converge the installed binary to `root:root` ownership and mode `0755`.
- Validate a newly built binary with `seriatim --version`.
- 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
@@ -49,123 +51,169 @@ and validation concerns.
- 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 Seriatim release artifacts.
- Removal or purge behavior.
- A shared build helper role or premature abstraction of the first
implementation.
- Full Ubuntu 26.04 platform-matrix or `arm64` integration infrastructure.
- Installation from prebuilt release artifacts or removal behavior.
- Detecting rebuild needs from Go compiler patch changes, fixed build-command
changes, or manually altered binary contents that still report the selected
version.
- 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 checks out Seriatim `v1.5.0` under `/usr/local/src/seriatim`, builds
it with the locally installed Go 1.26 toolchain, validates it, and installs a
root-owned executable at `/usr/local/bin/seriatim`. The installed command
reports `v1.5.0` through its global version flag.
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`.
A second application of the role makes no changes when the selected source,
compiler, build arguments, and installed binary are unchanged. Changing the
selected revision, compiler patch version, or effective build arguments causes
a rebuild. A failed build or validation does not replace an existing working
binary.
An immediate second application makes no changes. A changed Git checkout, a
missing binary, or a binary reporting another version causes one build. The
following application is again unchanged.
The managed source checkout is authoritative and may be reset to the selected
revision; local modifications beneath it are not preserved. Development users
may select a branch or commit explicitly, but released role and collection
manifests use immutable release tags.
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 all implementation, defaults, documentation,
and repository-local validation added by this feature.
- `../seriatim` is the read-only authority for the application build, version,
and CLI contracts.
- `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 only.
- The remaining role, collection, application, content, and proof-of-concept
repositories remain unchanged.
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; dedicated platform-matrix infrastructure is deferred.
- Go is installed from Snap with classic confinement. Builds use the local
toolchain with `GOTOOLCHAIN=local` rather than allowing automatic toolchain
downloads.
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 suite standardizes on Go channel `1.26/stable`, even though Seriatim's
current `go.mod` requires Go 1.25.
- Builds use `GOWORK=off`, `CGO_ENABLED=0`, and `-trimpath`.
- Release builds inject the selected release version into
`gitea.maximumdirect.net/eric/seriatim/internal/buildinfo.Version` with
`-ldflags`.
- A change to the installed Go compiler patch version is a build-input change
and triggers a rebuild.
- `/usr/local/src/seriatim` is fully Ansible-managed. The role enforces the
selected Git revision rather than preserving local changes.
- Source and installed binaries are owned by `root` and are not writable by
runtime operators.
- The build runs from the checked-out source using `/snap/bin/go`,
`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`, and
`seriatim_go_snap_channel`.
- Fixed executable paths, build flags, linker symbols, environment values, and
package paths are implementation details, not public variables.
- `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 ten
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. Read its version when it exists, without reporting a change.
8. Run the upstream Go build when the Git checkout changed, the binary is
absent, or its reported version differs from the selected version.
9. Converge source ownership and the installed binary's ownership and mode
with one `ansible.builtin.file` loop.
10. Validate the version after a build, without reporting a change.
For this fixed set of three 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 and post-build validation
then follow in their 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
Starting with Seriatim exercises the common source installation path without
mixing in application configuration, credentials, shared accounts, or pipeline
composition. This makes the first implementation small enough to review
carefully and allows its conventions to be corrected before being repeated.
This design uses the Git module's changed result as the natural signal that
source changed. The installed application's version is the only additional
state needed to decide whether a binary must be built. That preserves useful
convergence without maintaining a second database of compiler and build
inputs.
Using Go `1.26/stable` across the suite favors one predictable host toolchain
over selecting each application's minimum supported version. Rebuilding after
a compiler patch change preserves an honest relationship between recorded
build inputs and installed output. Keeping the first role self-contained also
avoids committing to a shared abstraction before repeated implementation has
shown which behavior is truly common.
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 with a clear diagnostic before modifying application state.
- Default role execution on the local Ubuntu 26.04 host installs or confirms
the required Git and Go build dependencies.
- The source checkout resolves to the commit referenced by tag `v1.5.0` and is
root-owned at `/usr/local/src/seriatim` by default.
- The role builds with the documented local-toolchain and version-injection
contract and installs `/usr/local/bin/seriatim` as `root:root` mode `0755`.
- `/usr/local/bin/seriatim --version` reports `v1.5.0`.
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 changed selected revision, Go compiler patch version, or effective build
argument invalidates recorded build state and rebuilds the binary.
- A deliberately failed staged build or version validation leaves a previously
installed working binary intact.
- Development revision overrides converge to the requested branch or commit
and discard unmanaged changes in the source checkout.
- Role defaults, metadata, README documentation, syntax validation, focused
automated checks, and local integration evidence are present in the owning
repository.
- A missing binary or a binary reporting the wrong version 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 six variables
named in this roadmap.
- 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
This feature depends only on access to the Seriatim Git repository, Ubuntu Snap
infrastructure, and Go module sources from the managed host.
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.
After review, the source-build conventions may be adopted by the Audita,
Scriptorium, Notarius, and Narratio roles. Generalization into shared tooling,
prebuilt-binary installation, removal behavior, and dedicated multi-platform
test infrastructure remain deferred until concrete experience justifies them.
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.
## Completion Evidence
## Potential Future Hardening
- `ansible-role-seriatim` commits `ac35c1f` through `efd4734` implement the
staged role contract, source installation, reproducible build, and integration
coverage.
- Remediation commits `c6c1907` through `6fb1aa2` close all findings recorded in
`docs/roadmap/remediation.md`, including malformed state and metadata drift.
- The complete integration suite passes on the local Ubuntu 26.04 development
host, restores the default installation, and finishes with a clean idempotent
convergence.
- The verified installation reports `seriatim version v1.5.0`, uses upstream
commit `0fc92f364316c874d366b00cdc884a33e1900b25`, and has consistent source,
binary, ownership, and build-state metadata.
- 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 dedicated Ubuntu release and architecture test matrices.
These are candidates for separately selected features if operational
experience or a changed threat model justifies them.

View File

@@ -0,0 +1,35 @@
# Feature 0002: Audita Source Installation and Configuration
Status: proposed
## Planning Note
Audita remains the likely next application role, but its previously drafted
roadmap and implementation plan were withdrawn before implementation. They
depended on the original Seriatim fingerprint, sidecar-state, staged-build,
and corruption-recovery architecture, which is no longer an approved pattern.
Do not implement this feature from the withdrawn plan. After the simplified
Seriatim role has been implemented and reviewed, discuss Audita again and
write a fresh feature roadmap using the workspace's minimal, module-driven
conventions.
## Preserved Upstream Research
- The latest selected immutable release was `v0.9.1`, resolving to commit
`a84941d68168a1ed9ea7423b6477ae8218be73f9` when inspected.
- The tag declares Go 1.24.0 and builds the package
`gitea.maximumdirect.net/eric/audita/cmd/audita` with `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and the documented release
linker flags.
- The release does not expose a CLI version command suitable for Seriatim's
version-based rebuild check. The simplest appropriate rebuild signal must be
decided during renewed roadmap discussion.
- Audita configuration schema version is `1`. Its native validator accepts
`audita config validate --config <path>` and reports `config is valid` for a
valid file.
- Default configuration discovery prefers
`/usr/local/etc/audita/config.yml` over `/etc/audita/config.yml`.
These facts should be revalidated against the authoritative `../audita`
repository before a new roadmap is approved.

View File

@@ -34,6 +34,14 @@ application contracts.
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
@@ -47,3 +55,8 @@ this section when the choice is mechanical and needs no durable rationale.
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

@@ -23,6 +23,14 @@ for scope, rationale, target end state, and acceptance criteria.
- 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.
@@ -57,6 +65,8 @@ State the single outcome delivered by this stage.
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
@@ -91,6 +101,8 @@ and subsequent consecutive integers as needed.
- 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

View File

@@ -1,507 +1,12 @@
# Implementation Plan 0001: Seriatim Source Installation
# Active Implementation Plan
Status: proposed
There is no approved implementation plan at present.
Target executor: GPT-5.6-Terra
Feature 0001 has been reopened with a revised, minimal specification at
`docs/roadmap/features/0001-seriatim-source-installation.md`. Prepare its
numbered staged implementation plan here only after that revised roadmap and
the workspace implementation conventions have been reviewed.
Feature roadmap:
`docs/roadmap/features/0001-seriatim-source-installation.md`
## Objective
Implement `ansible-role-seriatim` as an independently usable role that installs
Seriatim `v1.5.0` from its pinned Git source, builds it with the local Go 1.26
Snap toolchain, installs it safely, and converges idempotently. Preserve the
feature roadmap as the authority for scope, rationale, target state, and
acceptance criteria.
## Execution Rules
- Execute Stage 1 through Stage 4 in numeric order.
- Before each stage, confirm its preconditions and the working-tree state of
every repository named by that stage.
- Preserve unrelated and pre-existing changes. Stop if the owning repository
is not clean at a stage boundary unless the changes are the expected output
of the immediately preceding stage.
- Do not modify `rakestraw-ansible`, any upstream application repository, any
other role, or the collection.
- Do not make new product or architecture decisions. Stop and report any
conflict between this plan, the feature roadmap, and an upstream contract.
- Prefer `ansible.builtin` modules where they directly fit. Use the approved
`community.general.snap` module for channel-aware Snap management and pin
its collection dependency.
- Run every stage's validation before committing it. Do not begin a dependent
stage after a validation failure.
- Commit each completed stage in `ansible-role-seriatim` using the specified
commit intent. Do not push unless separately instructed.
- Treat `/usr/local/src/seriatim`, `/usr/local/bin/seriatim`, and the adjacent
role build-state directory as disposable managed test state during local
integration. Do not remove or alter unrelated host paths.
- Leave workspace roadmap and status files unchanged during implementation;
report stage commits and evidence for review instead.
## Starting State and Preconditions
- `ansible-workspace-dnd` and `ansible-role-seriatim` start clean on `main`.
- The active implementation plan has been reviewed and committed before
execution begins.
- The controller host is Ubuntu 26.04.1 `amd64` and has passwordless privilege
escalation available for the approved local integration run.
- Workspace tools are available at `../.venv/bin` from the role repository,
including Ansible Core 2.21.3 and ansible-lint 26.8.0.
- The managed host has working Snap infrastructure and outbound access to the
Seriatim Git repository, the Snap Store, and Go module sources.
- Upstream tag `v1.5.0` resolves to commit
`0fc92f364316c874d366b00cdc884a33e1900b25`.
- The upstream `v1.5.0` contract is:
- module requirement `go 1.25`;
- build package `./cmd/seriatim`;
- `CGO_ENABLED=0` and `-trimpath`;
- linker flags `-s -w -X
gitea.maximumdirect.net/eric/seriatim/internal/buildinfo.Version=<version>`;
- `seriatim --version` output `seriatim version <version>`.
## Repository Scope
- `ansible-role-seriatim` is the only implementation repository and owns every
role, test, dependency, and README change in this plan.
- `ansible-workspace-dnd` owns this plan and the feature roadmap but remains
read-only during out-of-band execution.
- `../seriatim` may be inspected as the authoritative upstream contract and
must remain unchanged.
- All other repositories in `workspace.yml` remain unchanged.
## Fixed Role Interface
Define and document these public defaults. All paths are managed-host paths.
| Variable | Default | Purpose |
| --- | --- | --- |
| `seriatim_version` | `v1.5.0` | Release identity expected from the installed binary |
| `seriatim_repository_url` | `https://gitea.maximumdirect.net/eric/seriatim.git` | Authoritative source repository |
| `seriatim_source_ref` | `{{ seriatim_version }}` | Git tag, branch, or commit to check out |
| `seriatim_build_version` | `{{ seriatim_version }}` | Value injected into Seriatim build metadata |
| `seriatim_source_dir` | `/usr/local/src/seriatim` | Fully managed source checkout |
| `seriatim_binary_path` | `/usr/local/bin/seriatim` | Installed executable |
| `seriatim_build_state_dir` | `/usr/local/src/seriatim.ansible-build-state` | Sidecar build inputs, fingerprint, and checksum |
| `seriatim_manage_build_dependencies` | `true` | Whether the role installs Git and Go |
| `seriatim_go_snap_channel` | `1.26/stable` | Go Snap channel |
| `seriatim_go_binary` | `/snap/bin/go` | Go executable used for version discovery and builds |
| `seriatim_go_build_flags` | `[-trimpath]` | Ordered arguments passed before `-ldflags` |
| `seriatim_go_ldflags` | upstream release linker flags using `seriatim_build_version` | Linker argument passed as one value |
| `seriatim_go_package` | `./cmd/seriatim` | Package built from the checkout |
`seriatim_source_ref` and `seriatim_build_version` are deliberately distinct.
A development branch or commit override must set an honest build-version value
as well as the source ref. Fixed build environment values are not public
overrides: `GOWORK=off`, `GOTOOLCHAIN=local`, and `CGO_ENABLED=0`.
## Stage 1: Establish the Role Contract and Static Validation
Completed: `ac35c1f` (`feat: define Seriatim role contract`)
### Objective
Create a conventional role skeleton with a fully specified variable contract,
argument validation, platform guards, dependency manifest, and syntax-test
entry point, without installing application state yet.
### Preconditions
- `ansible-role-seriatim` is clean on `main` and tracks `origin/main`.
- The workspace virtual environment passes
`../.venv/bin/ansible-playbook --version`.
- The feature roadmap and Fixed Role Interface above have no unresolved
conflicts.
### Owning Repository
`ansible-role-seriatim`
### Required Changes
1. Add the standard role paths `defaults/`, `meta/`, `tasks/`, `tests/`, and
`collections/`. Use YAML document markers and fully qualified module names.
2. Define every variable in the Fixed Role Interface in `defaults/main.yml`.
Do not expose aliases, compatibility variables, removal controls, or
configuration-file settings.
3. Add `meta/main.yml` with Eric Rakestraw as author, BSD-3-Clause licensing,
minimum Ansible Core 2.18, Ubuntu `resolute` platform metadata, source and
issue URLs, and tags appropriate to Seriatim and transcript processing.
4. Add `meta/argument_specs.yml`. Validate booleans, strings, lists, and paths
by type; require nonempty repository/ref/version/build values; and describe
every public variable.
5. Add `tasks/main.yml` and `tasks/validate.yml`. Run validation before every
task that can change the host. Assert:
- distribution is Ubuntu;
- distribution version is `26.04`;
- architecture is `x86_64` or `aarch64`;
- source, binary, and state paths are absolute and pairwise distinct;
- repository, source ref, build version, Go binary, build flags, linker
flags, and package are nonempty;
- build version contains no whitespace.
6. Pin `community.general` version `13.3.0` in
`collections/requirements.yml`. This collection requires Ansible Core 2.18
or newer and supplies the channel-aware `community.general.snap` module.
7. Extend `.gitignore` only for repository-local validation state, including
`.ansible/`, test output, and retry files. Preserve the existing general
ignore entries.
8. Add `tests/inventory` targeting localhost with local connection and an
explicit `/usr/bin/python3.14` interpreter. Add `tests/converge.yml` that
gathers facts, enables privilege escalation, and applies the repository
role through `ANSIBLE_ROLES_PATH`.
9. Replace the placeholder README with the role purpose, supported platform,
dependency-installation command, complete variable table, development-ref
rule, and an explicit statement that this stage does not yet install a
binary.
### Validation
From `ansible-role-seriatim`, run:
```sh
../.venv/bin/ansible-galaxy collection install \
-p .ansible/collections -r collections/requirements.yml
ANSIBLE_COLLECTIONS_PATH="$PWD/.ansible/collections" \
../.venv/bin/ansible-playbook -i tests/inventory tests/converge.yml \
--syntax-check
ANSIBLE_COLLECTIONS_PATH="$PWD/.ansible/collections" \
../.venv/bin/ansible-lint .
git diff --check
```
Expected result: `community.general` 13.3.0 is installed under the ignored
repository-local path, the test playbook passes syntax checking, ansible-lint
reports no violations, and Git reports no whitespace errors. Do not run the
converge playbook without `--syntax-check` during this stage.
### Completion Criteria
- The public defaults exactly match the Fixed Role Interface.
- Invalid platform and malformed-variable paths fail before host mutation.
- Static validation passes with the pinned collection available locally.
- Only `ansible-role-seriatim` contains implementation changes.
### Commit
Commit intent: `feat: define Seriatim role contract`
## Stage 2: Manage Build Dependencies and the Source Checkout
Completed: `b84b045` (`feat: manage Seriatim source prerequisites`)
### Objective
Implement idempotent Git and Go prerequisite management and converge the
root-owned Seriatim checkout to the selected source revision, without building
or installing the application binary yet.
### Preconditions
- Stage 1 is committed and its validation still passes.
- `snap info go` shows the configured `1.26/stable` channel.
- No unmanaged data that must be retained exists under the configured source
directory; that tree is deliberately authoritative and disposable.
### Owning Repository
`ansible-role-seriatim`
### Required Changes
1. Add `tasks/dependencies.yml` and include it after validation.
2. When `seriatim_manage_build_dependencies` is true:
- install the Ubuntu `git` package with `ansible.builtin.apt`, using a
reasonable cache-validity interval rather than refreshing on every run;
- install the single `go` Snap through `community.general.snap` with
`classic: true`, `channel: "{{ seriatim_go_snap_channel }}"`, and
`state: present`.
3. Whether dependency management is enabled or disabled, resolve Git and the
configured Go executable and fail clearly if either is unavailable. Run
`go version`, extract its semantic version, and require Go 1.25 or newer.
4. Add `tasks/source.yml` and include it after dependencies. Create the parent
source directory as `root:root` before cloning.
5. Use `ansible.builtin.git` with the configured repository and source ref,
`update: true`, `force: true`, and no shallow-clone assumption. Do not accept
host keys automatically and do not embed credentials.
6. Make the checkout fully managed: detect tracked or untracked dirt after the
Git task, reset tracked files to the selected checkout, and remove untracked
and ignored content with explicit Git commands only when dirt exists. Keep
the build-state sidecar outside the checkout so cleanup cannot remove it.
7. Enforce root ownership on the checkout and resolve the final commit with
`git rev-parse HEAD`. Assert that the default `v1.5.0` execution resolves to
`0fc92f364316c874d366b00cdc884a33e1900b25` in the local integration test;
nondefault refs record their actual resolved commit without that assertion.
8. Update the README to describe dependency opt-out behavior, channel
convergence, authoritative checkout cleanup, and requirements for private
repository authentication overrides without documenting any credentials.
### Validation
Run the Stage 1 static commands, then run:
```sh
ANSIBLE_COLLECTIONS_PATH="$PWD/.ansible/collections" \
ANSIBLE_ROLES_PATH="$(dirname "$PWD")" \
../.venv/bin/ansible-playbook -i tests/inventory tests/converge.yml
/snap/bin/go version
sudo git -C /usr/local/src/seriatim rev-parse HEAD
sudo test "$(stat -c '%U:%G' /usr/local/src/seriatim)" = root:root
```
Expected result: the play completes successfully without creating
`/usr/local/bin/seriatim`; Go is on the `1.26/stable` track and satisfies the
minimum version; the checkout resolves to the expected `v1.5.0` commit; and its
root directory is owned by `root:root`.
Create an untracked file and a tracked-file modification beneath the checkout,
rerun convergence, and verify both are removed. Run convergence once more and
require `changed=0` in the play recap.
### Completion Criteria
- Dependency management and opt-out behavior fail or converge as specified.
- Go channel and minimum-version validation are explicit and idempotent.
- Default source state is the expected clean, root-owned commit.
- Unmanaged checkout changes are discarded by a subsequent role run.
- A clean repeated run reports no changes.
### Commit
Commit intent: `feat: manage Seriatim source prerequisites`
## Stage 3: Build and Install Seriatim Reproducibly
Completed: `81313f0` (`feat: build and install Seriatim from source`)
### Objective
Add fingerprint-driven source compilation, staged validation, atomic binary
installation, and durable build-state recording without replacing a working
binary after a failed build.
### Preconditions
- Stage 2 is committed and its clean repeated convergence reports no changes.
- The default checkout is the expected `v1.5.0` commit.
- `/snap/bin/go version` reports a toolchain compatible with the upstream
module requirement.
### Owning Repository
`ansible-role-seriatim`
### Required Changes
1. Add `tasks/build.yml` after source convergence.
2. Construct one canonical build-input document containing at least:
- resolved source commit;
- complete `go version` output;
- configured Go binary path;
- build version;
- ordered build flags;
- linker flags;
- package path;
- fixed `GOWORK`, `GOTOOLCHAIN`, and `CGO_ENABLED` values.
Store the readable input document and its SHA-256 fingerprint in
`seriatim_build_state_dir` only after successful installation.
3. Record the installed binary's SHA-256 checksum beside the fingerprint.
Require a rebuild when the binary, any state file, or the checkout is
missing; when the desired fingerprint differs; when the installed checksum
differs; or when the installed version command fails or differs from
`seriatim version {{ seriatim_build_version }}`. Malformed or unreadable
state must cause a rebuild rather than an unhandled template failure.
4. When no rebuild is required, perform no mutating build or install task and
report no change.
5. When rebuilding, create a unique temporary directory with
`ansible.builtin.tempfile`. Invoke the configured Go binary with
`ansible.builtin.command` `argv`, the fixed environment, configured build
flags, one `-ldflags` value, a staged output path, and the configured package
from `seriatim_source_dir`.
6. Validate the staged binary before installation. Require exact stdout
`seriatim version {{ seriatim_build_version }}` and a successful exit from
`--version`.
7. Install the validated staged binary to `seriatim_binary_path` using an
atomic Ansible file operation with `root:root` ownership and mode `0755`.
Validate the installed binary again, calculate its checksum, and only then
write the build-input, fingerprint, and checksum state files.
8. Use an `always` cleanup path so temporary build content is removed after
success or failure. Never delete or overwrite the previously installed
binary or successful build state before a replacement has passed staged
validation.
9. Give command tasks precise `changed_when` and `failed_when` behavior so
ansible-lint passes and check/reporting semantics are honest.
10. Update the README with the exact build contract, rebuild triggers, state
location, ownership, safe replacement behavior, and development override
example setting both `seriatim_source_ref` and
`seriatim_build_version`.
### Validation
Run static validation, then converge and inspect:
```sh
ANSIBLE_COLLECTIONS_PATH="$PWD/.ansible/collections" \
ANSIBLE_ROLES_PATH="$(dirname "$PWD")" \
../.venv/bin/ansible-playbook -i tests/inventory tests/converge.yml
/usr/local/bin/seriatim --version
sudo stat -c '%U:%G %a' /usr/local/bin/seriatim
sudo find /usr/local/src/seriatim.ansible-build-state \
-maxdepth 1 -type f -print -exec sed -n '1,80p' {} \;
```
Expected result: the command prints exactly `seriatim version v1.5.0`; the
binary is `root:root` mode `755`; readable build inputs, fingerprint, and
checksum exist in the sidecar state directory; and no temporary staging
directory remains.
Run the same convergence immediately again and require `changed=0`. Then change
one effective build flag through an extra variable, run convergence, and
require the build/install tasks to report changes. Repeat with that override
and require `changed=0`; finally restore defaults and require exactly one more
rebuild followed by a clean repeat.
### Completion Criteria
- The installed binary matches the upstream version and ownership contract.
- Build state records every required input and the installed checksum.
- Missing, corrupt, or changed binary/state/input conditions rebuild.
- Unchanged convergence reports no changes.
- Temporary content is cleaned on both successful and failed task paths.
- Static validation remains clean.
### Commit
Commit intent: `feat: build and install Seriatim from source`
## Stage 4: Add Local Integration Regression Coverage
Completed: `efd4734` (`test: verify Seriatim source installation`)
### Objective
Turn the required local validation into a repeatable, failure-safe repository
test harness and complete the role's operator and maintainer documentation.
### Preconditions
- Stage 3 is committed, statically clean, and manually converges twice with the
second run reporting no changes.
- The default installed binary and build state are known-good before testing
deliberate failure paths.
- No unrelated local host data exists at the managed Seriatim paths.
### Owning Repository
`ansible-role-seriatim`
### Required Changes
1. Add `tests/verify.yml` with nonmutating assertions for:
- supported platform facts;
- source commit and cleanliness;
- source, binary, and state ownership;
- binary mode;
- exact installed version output;
- presence and consistency of build inputs, fingerprint, and installed
checksum.
2. Add an executable `tests/integration` shell driver that locates the
workspace virtual environment relative to the repository, installs the
pinned collection into `.ansible/collections`, exports local collection and
role paths, and runs syntax checking plus ansible-lint before host mutation.
3. Have the driver run default convergence, verification, and an immediate
second convergence. Parse the second recap and fail unless `changed=0` and
`failed=0`.
4. Test the mutation guard with separate plays that override gathered facts to
represent an unsupported distribution, Ubuntu release, and architecture.
Each play must fail in validation before a mutating task; capture the
installed binary checksum and successful state beforehand and require both
to remain unchanged afterward.
5. Test source authority by creating both a tracked modification and an
untracked file in the managed checkout, converging, and verifying a clean
checkout at the expected commit.
6. Test compiler-input invalidation with a temporary Go wrapper. Its `version`
path must report a distinct valid Go 1.26 patch identity while all other
commands delegate to `/snap/bin/go`. Converge with
`seriatim_go_binary` set to the wrapper, require a rebuild, repeat and
require idempotence, then restore the default Go path and require one final
rebuild followed by idempotence.
7. Test failure preservation with a second temporary Go wrapper that reports a
valid version but fails the build invocation. Capture the installed binary
checksum and successful state files before the expected failed play. After
failure, require the binary checksum and state contents to be byte-for-byte
unchanged and require `seriatim --version` still to report `v1.5.0`.
8. Use a temporary directory and cleanup trap for wrappers and captured test
output. The driver must restore default role convergence before exit where
possible and must never delete unrelated host content.
9. Update the README with development-environment setup, static validation,
local integration warnings, the single test-driver command, expected host
mutations, and recovery instructions limited to rerunning default
convergence.
10. Remove any Stage 1 wording that says installation is not implemented.
### Validation
From `ansible-role-seriatim`, run:
```sh
tests/integration
git diff --check
git status --short
```
Expected result: the driver completes every static, convergence, idempotence,
source-cleanup, compiler-change, failure-preservation, and final verification
case; the installed host state ends at default Seriatim `v1.5.0`; Git reports
no whitespace errors; and only intended repository changes are present before
the stage commit.
After committing, run `tests/integration` once more. The repository must remain
clean afterward.
### Completion Criteria
- One documented command reproduces all MVP validation on the local Ubuntu
26.04 proxy.
- Idempotence, compiler-version invalidation, managed-source cleanup, exact
versioning, and failed-build preservation have executable regression
coverage.
- README instructions match the implemented role and test behavior.
- The post-commit integration run passes and leaves the role repository clean.
### Commit
Commit intent: `test: verify Seriatim source installation`
## Final Validation and Handoff
After Stage 4, run:
```sh
tests/integration
git log --oneline -4
git status --short --branch
cd ..
./scripts/status
```
The implementation handoff must report:
- the four stage commit hashes in order;
- the final `seriatim --version` output;
- the final source commit, Go version, binary checksum, ownership, and mode;
- the clean-repeat recap showing `changed=0` and `failed=0`;
- confirmation that deliberate build failure preserved the prior binary and
state;
- every deviation from this plan or feature roadmap;
- any unresolved findings or recommended follow-up work.
Do not mark Feature 0001 `done` and do not edit workspace status during the
out-of-band execution. Completion requires subsequent review.
## Progress Notes
- Stage 1 completed in `ansible-role-seriatim` commit `ac35c1f`.
- Stage 2 completed in `ansible-role-seriatim` commit `b84b045`.
- Stage 3 completed in `ansible-role-seriatim` commit `81313f0`.
- Stage 4 completed in `ansible-role-seriatim` commit `efd4734`.
The prior Audita plan was withdrawn because it propagated the superseded
Seriatim build-state and hardening architecture. Git history preserves that
research, but those execution instructions must not be used.

View File

@@ -50,17 +50,21 @@ role will manage the native configuration needed to connect to it.
- 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 into a staging location, validate the result, and then install
the binary at `/usr/local/bin/<app>` with `root:root` ownership and mode
`0755`. A failed build must not replace a working installed binary.
- 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`.
- Build state must account for the checked-out commit, Go toolchain, and build
arguments so that roles rebuild when a relevant input changes rather than
relying only on the existence of the installed binary.
- Each application role exposes variables for its repository, selected
version or revision, source directory, binary path, and build settings.
- Roles normally rebuild when the Git task reports a changed checkout, the
binary is absent, or an application-level version or smoke check shows that
the installed binary is unsuitable. They 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, and Go Snap channel.
Fixed details of the upstream build contract need not become public
variables.
### Go toolchain
@@ -131,6 +135,13 @@ application-role releases in one source repository.
- 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
@@ -213,6 +224,12 @@ remain to be designed.
- Deploying or managing WhisperX
- Versioned Narratio prompt-library releases and 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

View File

@@ -1,174 +1,19 @@
# Feature 0001 Remediation Findings
# Feature 0001 Prior Remediation Record
Status: resolved
Historical record: superseded
## Review Scope
The original Feature 0001 review required increasingly elaborate recovery for
build-state files, metadata drift, custom path shapes, and symbolic links.
Those findings were resolved in `ansible-role-seriatim` commits `c6c1907`
through `6fb1aa2`, but the resulting architecture was later rejected as
disproportionate to the MVP.
This review compared `ansible-role-seriatim` commits `ac35c1f` through
`efd4734` with the Feature 0001 roadmap and staged implementation plan. It also
ran the committed static and integration validation and performed targeted
state-corruption, permission-drift, and custom-path checks on the managed local
installation.
The authoritative replacement specification is
`docs/roadmap/features/0001-seriatim-source-installation.md`. It deliberately
removes persistent build state and treats unusual corruption, adversarial path
redirection, exact compiler-input tracking, and transactional replacement as
potential future hardening rather than current requirements.
The four planned implementation stages are structurally present and the
committed integration suite passes. The findings below are gaps that must be
addressed before Feature 0001 is marked complete or its patterns are copied to
other application roles.
## Finding 1: Build-input state content is not part of convergence
Severity: high
`tasks/build.yml` checks whether `build-inputs.json` exists but never reads or
compares its content. The rebuild decision trusts `fingerprint.sha256`
independently. An empty, corrupted, stale, or replaced build-input document is
therefore accepted as converged when the fingerprint and binary checksum files
remain unchanged.
This diverges from the plan's requirement that malformed or unreadable state
cause a rebuild and from the role's claim that readable inputs and their
fingerprint describe the installed result. A targeted test truncated
`build-inputs.json`; convergence returned `changed=0` and `failed=0`, while the
subsequent verification play correctly failed its input/fingerprint assertion.
Required remediation:
- Read the stored build-input document safely during convergence.
- Require its exact canonical content to match the desired build inputs and
require its SHA-256 digest to match the stored and desired fingerprint.
- Treat missing, unreadable, malformed, or inconsistent input state as a
rebuild condition rather than an unhandled failure.
- Extend `tests/integration` to corrupt or replace `build-inputs.json`, verify
that convergence repairs it, and verify that the following run is
idempotent.
## Finding 2: Managed ownership and modes drift without repair
Severity: medium
The binary's checksum and version participate in the rebuild decision, but its
owner, group, and mode do not. Binary metadata is set only inside the rebuild
block. Build-state directory and file metadata are likewise set only after a
build. A content-identical installation can therefore remain in an unsafe or
incorrect metadata state indefinitely.
A targeted test changed `/usr/local/bin/seriatim` from mode `0755` to `0777`.
Convergence returned `changed=0` and left mode `0777` in place. This violates
the target state requiring a root-owned, non-operator-writable binary. The same
design leaves drifted state-file ownership and permissions uncorrected.
Required remediation:
- Converge `seriatim_binary_path` to `root:root` mode `0755` whenever a valid
installed regular file exists, without forcing an unnecessary rebuild.
- Converge `seriatim_build_state_dir` to `root:root` mode `0755` and its three
managed files to `root:root` mode `0644` on every successful role run.
- Treat unexpected file types, including a directory at the binary path, as a
clear validation or repair condition rather than passing them into the build
copy operation.
- Add integration cases that drift binary and build-state metadata, require
one repairing run, and require an idempotent repeat.
## Finding 3: A configurable binary path requires a pre-existing parent
Severity: medium
`seriatim_binary_path` is a documented public path override, but the role does
not create or validate its parent directory. `ansible.builtin.copy` consequently
fails after a successful build when the configured parent is absent. A
targeted run using `/tmp/seriatim-review-missing-parent/seriatim` failed with
`Destination directory ... does not exist`.
Required remediation:
- Inspect the configured binary parent before building.
- Fail clearly if an existing parent is not a directory.
- Create a missing parent as `root:root` mode `0755` without changing ownership
or mode on an already existing shared directory.
- Add an isolated integration case proving that a nondefault binary path with
a missing parent installs, validates, and converges idempotently.
## Finding 4: Role metadata and privilege documentation are incomplete
Severity: low
Stage 1 required role source and issue information, but `meta/main.yml` omits
the supported `issue_tracker_url` field. The README also does not state plainly
that consumers must apply the role with privilege escalation, even though it
manages packages, snaps, root-owned source, and `/usr/local/bin`.
Required remediation:
- Add the role repository's Gitea issue tracker to `meta/main.yml`.
- Add role repository and issue links to the README where appropriate.
- State explicitly that the consuming play must use `become: true` or provide
equivalent root privileges.
- Re-run metadata/schema validation and ansible-lint.
## Remediation Completion Criteria
- All four findings are addressed in `ansible-role-seriatim`.
- Static validation and the expanded `tests/integration` suite pass.
- Targeted corruption, metadata-drift, and alternate-path cases converge to
the documented state and then report `changed=0` on an immediate repeat.
- The default local installation ends at Seriatim `v1.5.0`, source commit
`0fc92f364316c874d366b00cdc884a33e1900b25`, with a clean checkout and
consistent build state.
- The role and workspace repositories are clean, and remediation commits are
ready for review before Feature 0001 is marked complete.
## Resolution Evidence
- Finding 1 was resolved by `ansible-role-seriatim` commit `c6c1907`.
- Finding 2 was resolved by `ansible-role-seriatim` commit `f2c1b1a`.
- Finding 3 was resolved by `ansible-role-seriatim` commit `92906eb`.
- Finding 4 was resolved by `ansible-role-seriatim` commit `07dd736`.
- Malformed state-object recovery was hardened by
`ansible-role-seriatim` commit `ca49dae` during the completion audit.
- The expanded `tests/integration` suite passed after all remediation commits
and restored the default Seriatim installation.
## Completion Review
The four original findings are resolved, and the expanded integration suite
passes. A focused review of the malformed-state recovery identified one
additional edge case, which has also been resolved.
## Finding 5: A malformed build-state directory is not handled
Severity: medium
`tasks/build.yml` inspects the three state files beneath
`seriatim_build_state_dir` without first inspecting the state-directory path.
If that configured path exists as a regular file, the first
`ansible.builtin.stat` fails with `Not a directory`. This is an unhandled
malformed-state failure rather than the planned recovery behavior. A targeted
run with an otherwise valid custom binary confirmed that the role exits before
rebuilding or converging the state directory. A second targeted run using a
symbolic link as the state-directory path succeeded and wrote all three
root-owned state files into the link target while leaving the configured path
as a symbolic link.
Required remediation:
- Inspect `seriatim_build_state_dir` before inspecting any child state path.
- Define and implement deliberate behavior for an existing non-directory
object. Because the state directory is fully managed, replacing that object
and rebuilding is consistent with the existing malformed-state-file
behavior; alternatively, fail with a purpose-written assertion if preserving
an unexpected object is preferred.
- Ensure an existing symbolic link is not silently treated as the managed
state directory or used to redirect root-owned state writes.
- Add integration coverage for the selected non-directory behavior and require
an idempotent immediate repeat after recovery when recovery is supported.
Resolution:
- `ansible-role-seriatim` commit `6fb1aa2` makes the build-state directory
authoritative, replacing regular files and symbolic links with a root-owned
directory before inspecting child state.
- Integration coverage confirms repair and immediate idempotence for both
regular-file and symbolic-link drift, and confirms that the symbolic-link
target remains untouched.
- The complete integration suite passes and restores a verified default
installation.
This file is retained only to explain the historical commit sequence. It is
not an active remediation specification and must not be used as a template for
another role.

View File

@@ -4,7 +4,8 @@ Last updated: 2026-09-07
Current milestone: MVP standalone application roles
Current focus: Select the next standalone application-role feature.
Current focus: Review the revised Feature 0001 specification and prepare a
minimal Seriatim simplification plan.
| ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- |
@@ -13,11 +14,12 @@ Current focus: Select the next standalone application-role feature.
| M0-03 | Tracked MVP roadmap | workspace | done | `docs/roadmap/mvp.md` established |
| 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 | ready | Select the next item from the roadmap |
| M1-02 | Standalone application roles | role repositories | in_progress | Seriatim complete; select the next application role |
| M1-01 | Remaining MVP design decisions | workspace | ready | Resume after the revised Seriatim pattern is accepted |
| M1-02 | Standalone application roles | role repositories | in_progress | Simplify Seriatim before continuing to other roles |
| 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 | Role commit `6fb1aa2`; feature and remediation acceptance checks pass |
| F0001 | Install Seriatim from pinned source | ansible-role-seriatim | ready | Revised roadmap ready; staged simplification plan is next |
| F0002 | Install and configure Audita | ansible-role-audita | proposed | Replan after the simplified Seriatim role is reviewed |
## Updating This File