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

393 lines
18 KiB
Markdown

# Implementation Plan 0003: Install and Configure Notarius
Status: in_progress
Target executor: GPT-5.6-Terra
Feature roadmap:
[Feature 0003: Notarius Source Installation and Configuration](features/0003-notarius-source-installation-and-configuration.md)
Active plan location: `docs/roadmap/implementation.md`
## Objective
Implement the small, independently usable `rakestraw.notarius` role defined
by Feature 0003. Install Notarius from its pinned source release, build its
executable on the managed host, and manage its versioned YAML configuration
through the approved nullable field-specific interface.
The feature roadmap remains authoritative for scope, rationale, target end
state, and acceptance criteria.
## Execution Rules
- Execute Stage 1 and Stage 2 in numeric order.
- Before each stage, confirm its preconditions and the owning repository's
working-tree state.
- Modify only `ansible-role-notarius`. Treat this workspace, `../notarius`,
`rakestraw-ansible`, and every other repository as read-only.
- Preserve unrelated changes. Stop if the role repository is unexpectedly
dirty at a stage boundary.
- Follow `docs/conventions.md` and the Feature 0003 simplest viable
implementation. Trust the idempotence, change detection, check-mode
behavior, and error handling of APT, Snap, `file`, `git`, and `template`.
- Inspect only binary existence because that result is independently required
to decide whether the arbitrary build command must run.
- Put the two rebuild conditions directly on the build task. Do not add an
intermediate fact, handler, or handler flush.
- Do not execute Notarius from production role tasks. Executable and
configuration validation belong only in repository-local integration tests.
- Do not add configuration assembly facts, preliminary configuration probes,
fingerprints, checksums, sidecar state, manual Git cleanup, staged
replacement, compiler inspection, version interrogation, or out-of-band
drift detection.
- Render configuration with one template task. Use `is not none` for optional
values, omit empty parent sections, and serialize strings and mappings with
filters rather than hand-written quoting.
- Accept the already composed `notarius_pipelines` mapping. Do not load
pipeline files or implement merging, precedence, or a second configuration
interface inside the role.
- Use fully qualified collection names and `argv` for command execution.
- Run every 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/notarius`, `/usr/local/bin/notarius`, and
`/usr/local/etc/notarius/config.yml` as disposable role-managed test state.
## Starting State and Preconditions
- `ansible-role-notarius` is clean on `main` at initial commit `f8a3e11`,
tracking `origin/main` without divergence.
- This plan and the ready Feature 0003 roadmap are committed before
out-of-band execution begins.
- Feature 0001 established the accepted minimal source-build task flow, and
Feature 0002 established the nullable field-specific configuration and
conditional-template conventions.
- The local controller and managed host are Ubuntu 26.04 `amd64`, 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 tag `v0.6.0` resolves to
`77ae132e5609916da40dcd4fcc749c000a63cbac` and declares Go 1.25.5.
- The release build uses package `./cmd/notarius`, `CGO_ENABLED=0`,
`GOWORK=off`, `GOTOOLCHAIN=local`, `-trimpath`, and linker flag
`-X gitea.maximumdirect.net/eric/notarius/internal/buildinfo.Override=<version>`.
- Configuration schema version 4 accepts a document containing only
`version: 4`. `notarius config validate --config <path>` validates a managed
file without requiring a selected pipeline.
- Tag `v0.5.0`, commit
`61436d7c186af57b06004e090ceac898e83cdb71`, remains available for the
checkout-change test.
## Repository Scope
- `ansible-role-notarius` owns all implementation, public interface, template,
README, dependency, metadata, and repository-local test changes.
- `ansible-workspace-dnd` owns the roadmap, plan, and aggregate status but
remains unchanged during out-of-band implementation.
- `../notarius` is the authoritative read-only build, CLI, and configuration
contract.
- `rakestraw-ansible` is a read-only style and deployment-policy reference.
- Every other repository in `workspace.yml` remains unchanged.
## Fixed Public Interface
Implement exactly the eight installation variables and fourteen
configuration variables in the Feature 0003 roadmap, with matching argument
specifications.
Use these argument-specification types:
- `str`: `notarius_version`, `notarius_repository_url`,
`notarius_go_snap_channel`, `notarius_promptkit_profile_dir`,
`notarius_promptkit_profile_file`,
`notarius_promptkit_local_backend_endpoint`,
`notarius_output_directory`, `notarius_cache_chunk_plans_mode`,
`notarius_cache_chunk_plans_directory`,
`notarius_cache_checkpoints_directory`, and `notarius_debug_directory`;
- `path`: `notarius_source_dir`, `notarius_binary_path`,
`notarius_go_binary`, and `notarius_config_path`;
- `bool`: `notarius_manage_build_dependencies` and
`notarius_cache_checkpoints_enabled`;
- `int`: `notarius_config_version`,
`notarius_promptkit_local_backend_concurrency_limit`,
`notarius_concurrency_total_llm`, and
`notarius_concurrency_stage_workers_extract`;
- `dict`: `notarius_pipelines`.
The eight installation variables and `notarius_config_version` are required
by the argument specification because they have concrete defaults. The other
thirteen configuration variables are optional and default to YAML null. Do not
add `notarius_config`, a template override, a raw-file variable, or hidden
configuration defaults.
## Stage 1: Implement the Complete Minimal Role
### Objective
Create the role contract, concise production task flow, conditional
configuration template, documentation, and baseline integration harness that
install and configure Notarius idempotently.
### Preconditions
- The starting revisions and upstream contracts remain unchanged.
- `ansible-role-notarius` has no uncommitted changes.
- The default managed paths contain no data that must be preserved.
### Owning Repository
`ansible-role-notarius`
### 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 `notarius`, namespace `rakestraw`, Ubuntu 26.04 support,
Ansible Core 2.18 or newer, an empty role dependency list, and the canonical
issue tracker. Pin `community.general` to version `13.3.0`.
3. Define exactly the twenty-two public variables from the roadmap. Keep all
thirteen optional configuration values explicitly null. Mirror the public
names and the types above in `meta/argument_specs.yml`; do not encode
Notarius's semantic validation rules in Ansible.
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 `notarius_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 `notarius_version` with `ansible.builtin.git`, `force: true`,
and register the module result;
6. inspect only `notarius_binary_path` with `ansible.builtin.stat`;
7. build directly to `notarius_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;
9. render `templates/config.yml.j2` to `notarius_config_path` as
`root:root` mode `0644` with one `ansible.builtin.template` task.
5. Invoke `notarius_go_binary` with `ansible.builtin.command` and `argv` from
`notarius_source_dir`. Use the fixed package, environment, trim-path flag,
linker symbol, selected version, and output path from the upstream build
contract. This build is the only production command; rely on the command
module's ordinary changed result when it runs.
6. Put `notarius_checkout.changed or not notarius_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 every task
that manages root-owned state. Do not require play-level privilege
escalation.
8. Make the template always emit `version`. Emit these optional structures
only when their variables are non-null:
- `promptkit`, with direct profile-source fields and nested `local_backend`;
- `pipelines`, serialized from the caller-supplied mapping without
structural rewriting;
- `concurrency`, with nested `stage_workers.extract`;
- `output`;
- `cache`, with independently conditional `chunk_plans` and `checkpoints`;
- `debug`.
9. Preserve explicit false, zero, empty string, and empty mapping values by
testing presence with `is not none`. Serialize scalar values and the
pipeline mapping safely; do not build a configuration dictionary in a fact
or reproduce application defaults.
10. Replace the placeholder README with concise documentation covering the
supported platform, fact and privilege requirements, all public variables,
dependency opt-out, build behavior, rebuild triggers, null-as-omission
behavior, secrets boundary, native `pipelines` mapping, caller-side
`combine` example, and test effects.
11. Add a baseline integration driver that installs the pinned collection into
a private temporary location, runs syntax checking and production-profile
ansible-lint, converges without play-level `become`, and verifies:
- source commit `77ae132e5609916da40dcd4fcc749c000a63cbac` and recursive
`root:root` source ownership;
- binary `root:root` ownership, mode `0755`, and output
`notarius v0.6.0`;
- configuration `root:root` ownership, mode `0644`, and parsed content
exactly equal to `{"version": 4}`;
- native configuration validation succeeds; and
- an immediate repeat reports `changed=0` and `failed=0`.
12. Keep repository paths relative and temporary test artifacts outside the
repository. The integration driver's cleanup must restore the default
release and minimal configuration.
### Validation
From `ansible-role-notarius`, run:
```sh
tests/integration
git diff --check
git status --short
```
Expected result: syntax and lint pass; source resolves to
`77ae132e5609916da40dcd4fcc749c000a63cbac`; the executable reports
`notarius v0.6.0` and is `root:root` mode `0755`; the configuration parses as
exactly `{"version": 4}`, is `root:root` mode `0644`, and passes Notarius's
native validation; the immediate repeat reports `changed=0` and `failed=0`;
only intended Stage 1 changes remain.
### Completion Criteria
- Exactly eight installation defaults and fourteen configuration defaults
exist with matching argument specifications.
- Production tasks follow the nine-operation roadmap flow without unrequested
probes, persisted private state, handlers, or production validation.
- The template implements every public configuration field and the required
omission semantics without a parallel interface.
- README, metadata, dependencies, tasks, template, and baseline tests agree.
- Baseline integration passes and proves default convergence and idempotence.
- No repository outside `ansible-role-notarius` changed.
### Commit
Commit message: `Install and configure Notarius`
## Stage 2: Add Focused Behavioral Coverage
### Objective
Prove the selected rebuild triggers, independent configuration convergence,
inventory-side pipeline composition, falsey-value rendering, dependency
opt-out, metadata repair, platform guard, and restored default state without
expanding production behavior.
### Preconditions
- Stage 1 is committed and `ansible-role-notarius` is otherwise clean.
- Stage 1 integration passes.
- The default and alternate upstream revisions remain available.
### Owning Repository
`ansible-role-notarius`
### Required Changes
1. Extend `tests/integration` using strict shell options,
repository-relative paths, a private temporary directory, and cleanup that
restores `v0.6.0` and the minimal configuration.
2. Retain baseline convergence, verification, native configuration validation,
and clean repeat, then test:
- an absent binary causes one build followed by an unchanged run;
- dependency opt-out with a caller-supplied Go executable causes one build
through that executable followed by an unchanged run;
- binary metadata drift is repaired by `ansible.builtin.file` without
running the build, followed by an unchanged run;
- selecting `v0.5.0` causes one checkout rebuild, installs commit
`61436d7c186af57b06004e090ceac898e83cdb71`, and reaches an unchanged run;
- restoring `v0.6.0` causes one checkout rebuild, restores the default
commit, and reaches an unchanged run;
- unsupported distribution, Ubuntu release, and architecture facts fail
before creating application state at isolated temporary paths.
3. Add configuration verification that parses the YAML and compares native
structures rather than relying on whitespace or key order. Cover:
- the exact minimal document;
- a valid representative configuration spanning `promptkit`, `pipelines`,
`concurrency`, `output`, both cache subsections, and `debug`;
- each PromptKit profile-source field in separate valid scenarios because
Notarius makes them mutually exclusive;
- null omission and parent-section omission;
- explicit false, zero, empty string, and empty mapping rendering, without
requiring semantically invalid falsey examples to pass native validation;
- restoration to the exact minimal document.
4. Exercise caller-side pipeline composition directly. Define at least two
inventory mappings, each keyed by a distinct pipeline ID, assign
`notarius_pipelines` with the ordinary `combine` filter, and prove both
native definitions are rendered without role-side rewriting and pass
`notarius config validate`.
5. Prove each configuration-only transition changes the template task, skips
the build task, and reaches an unchanged immediate repeat. Do not add
production tasks to facilitate testing.
6. Inspect captured task output only where necessary to distinguish build,
metadata, and configuration convergence. Fail on hidden task failures or
unexpected changes in idempotence runs.
7. Limit test mutation to the three declared managed paths and the driver's
private temporary directory. Leave the default release and minimal
configuration installed after successful or failed test execution when
restoration is possible.
8. Add no coverage that implies production support for version interrogation,
fingerprints, checksums, compiler drift, source dirt, staged build failure,
malformed adversarial host state, role-side pipeline merging, or production
configuration preflight.
9. Update the README test section to describe the focused suite, pipeline
composition coverage, and managed-host effects.
### Validation
From `ansible-role-notarius`, run:
```sh
tests/integration
git diff --check
git status --short
```
Then confirm the restored installation:
```sh
sudo git -C /usr/local/src/notarius rev-parse HEAD
sudo stat -c '%U:%G %a' /usr/local/bin/notarius
sudo stat -c '%U:%G %a' /usr/local/etc/notarius/config.yml
/usr/local/bin/notarius --version
/usr/local/bin/notarius config validate --config /usr/local/etc/notarius/config.yml
```
Expected result: all focused and negative cases pass; every required repeat
reports `changed=0` and `failed=0`; source is restored to
`77ae132e5609916da40dcd4fcc749c000a63cbac`; metadata is `root:root 755` for
the binary and `root:root 644` for configuration; the executable reports
`notarius v0.6.0`; and native validation accepts the restored minimal file.
### Completion Criteria
- Every Feature 0003 acceptance criterion has direct static or integration
evidence.
- Configuration coverage proves nullable field rendering, empty-parent
omission, intentional falsey values, and native validity where applicable.
- Inventory-defined pipeline maps compose into the native field without any
role-side merge mechanism.
- Configuration-only convergence demonstrably does not rebuild Notarius.
- Coverage remains limited to the selected operational contract.
- README, interface, tasks, template, and tests agree.
- Default local state is restored and idempotent.
- No repository outside `ansible-role-notarius` changed.
### Commit
Commit message: `Add focused Notarius integration coverage`
## Final Validation and Handoff
After Stage 2, run:
```sh
tests/integration
git log --oneline -2
git status --short --branch
cd ..
./scripts/status
```
Report the two commit hashes, final integration and repeat results, restored
source commit, file metadata, executable version, native
configuration-validation result, any deviation or remaining concern, and any
complexity beyond this task flow with the acceptance criterion that required
it.
Do not edit workspace planning files, mark Feature 0003 `done`, or push during
out-of-band execution. Completion requires subsequent review.
## Progress Notes
- Stage 1 completed in `ansible-role-notarius` commit `287fc4a`.
- Stage 2 completed in `ansible-role-notarius` commit `733a194`.
- Post-implementation review passed the complete integration suite and opened
the findings in `docs/roadmap/remediation.md`.