Complete the Notarius feature

This commit is contained in:
2026-09-08 23:53:06 +00:00
parent f87962ca13
commit 4177b4de81
5 changed files with 55 additions and 450 deletions

View File

@@ -44,6 +44,11 @@
the role's own implementation. Put implementation verification in
repository-local tests unless the specification explicitly requires runtime
validation during convergence.
- For an unavoidable `command` or `shell` task, declare the operation's change
semantics as required by ansible-lint. A conditionally executed mutation may
use `changed_when: true`; a read-only command should use
`changed_when: false`. This describes an imperative operation and does not
replace the idempotence of a state-management module.
- Apply `become: true` to individual tasks that require elevated privileges.
Do not require callers to escalate an entire play merely to use a role.
- Complexity requires a requirement. Every additional task, conditional,

View File

@@ -1,6 +1,6 @@
# Feature 0003: Notarius Source Installation and Configuration
Status: in_progress
Status: done
## Summary
@@ -327,10 +327,10 @@ a configured pipeline, input artifacts, PromptKit assets and endpoints, and
secret environment variables; those belong to consumers or later suite-level
work.
The approved staged plan is maintained at
`docs/roadmap/implementation.md`. The pipeline role can supply its D&D
definitions through `notarius_pipelines` and select the other field-specific
values after the standalone interface is implemented and reviewed.
The role was implemented in `ansible-role-notarius` commits `287fc4a` and
`733a194`, then finalized by remediation commit `eb4f511`. Its complete
integration suite passes. The pipeline role can now supply its D&D definitions
through `notarius_pipelines` and select the other field-specific values.
## Potential Future Hardening

View File

@@ -1,392 +1,12 @@
# Implementation Plan 0003: Install and Configure Notarius
# Implementation Plan
Status: in_progress
Status: pending
Target executor: GPT-5.6-Terra
No implementation plan is currently active. Feature 0003 was completed in
`ansible-role-notarius` commits `287fc4a`, `733a194`, and `eb4f511`. Its
durable scope remains in
[the Feature 0003 roadmap](features/0003-notarius-source-installation-and-configuration.md),
and its review history remains in [the remediation record](remediation.md).
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`.
Select and approve the next feature roadmap before replacing this notice with
a staged implementation plan.

View File

@@ -1,84 +1,64 @@
# Feature 0003 Remediation Review
Status: open
Status: resolved
Reviewed implementation commits:
- `287fc4a Install and configure Notarius`
- `733a194 Add focused Notarius integration coverage`
The role's complete integration suite passes. The production architecture is
substantially complete and follows the selected nine-operation flow, but the
following issues should be corrected before Feature 0003 is marked done.
Remediation commit:
- `eb4f511 Correct Notarius metadata and dependency coverage`
## Finding 1: Correct the Galaxy License Metadata
Severity: medium
`ansible-role-notarius/meta/main.yml` declares `license: BSD-3-Clause`, while
the repository's retained `LICENSE` file is CC0 1.0 Universal. Package metadata
must not misstate the terms under which the repository is distributed.
`ansible-role-notarius/meta/main.yml` declared `license: BSD-3-Clause`, while
the retained repository license is CC0 1.0 Universal.
### Required Remediation
### Resolution
- Change the Galaxy license identifier to `CC0-1.0`, consistent with the
repository license and the other standalone roles that use the same license.
- Run metadata lint as part of the complete integration suite.
The Galaxy license identifier is now `CC0-1.0`, consistent with the repository
license.
## Finding 2: Remove the Redundant Build Change Override
Severity: low
Status: withdrawn
The `Build Notarius` task sets `changed_when: true`. The
`ansible.builtin.command` module already reports a successful executed command
as changed, and the task's `when` expression already determines exactly when a
build occurs. The override adds no behavior and conflicts with the convention
to trust module behavior and require a reason for every additional directive.
The initial review treated `changed_when: true` on the conditionally executed
build command as redundant. Validation after removing it failed ansible-lint's
`no-changed-when` production rule.
### Required Remediation
### Resolution
- Remove `changed_when: true` from the production build task.
- Retain the existing rebuild expression unchanged:
`notarius_checkout.changed or not notarius_binary.stat.exists`.
- Run the complete integration suite to confirm that build runs still report
changed and immediate repeats remain clean.
The directive remains in place. Unlike a desired-state module, the imperative
build command must explicitly declare its change semantics for lint. The
existing `when` expression still determines whether the command runs, and
`changed_when: true` accurately reports that every executed build changes the
binary. The distinction is now documented in `docs/conventions.md`.
## Finding 3: Make the Dependency-Opt-Out Test Prove the Selected Go Binary
Severity: low
The integration suite sets `notarius_go_binary` to a symlink whose target is
`/snap/bin/go`. The test succeeds with the current implementation, but it would
also succeed if the build task ignored `notarius_go_binary` and hard-coded
`/snap/bin/go`. It therefore does not establish the acceptance criterion that
a caller-supplied Go executable is actually used.
The original integration test pointed `notarius_go_binary` at a symlink to
`/snap/bin/go`, so it did not prove that the configured path was actually
invoked.
### Required Remediation
### Resolution
- Replace the symlink with a small executable wrapper in the suite's private
temporary directory.
- Have the wrapper record its invocation and then delegate to `/snap/bin/go`.
- Assert that the invocation record was written during the dependency-opt-out
build, while retaining the existing clean-repeat assertion.
- Keep the wrapper and its record in the existing private temporary directory;
do not add production behavior.
The test now supplies a wrapper in its private temporary directory. The
wrapper records its invocation before delegating to `/snap/bin/go`, and the
suite asserts that the record exists after the dependency-opt-out build.
## Review Evidence
## Final Validation
The review ran from `ansible-role-notarius`:
The complete `tests/integration` suite passed after remediation with Ansible
Core 2.21.3 and ansible-lint 26.8.0. Production-profile lint passed, every
selected build and configuration behavior remained valid, all required repeat
runs were clean, and the suite restored Notarius `v0.6.0` with the minimal
`version: 4` configuration.
```sh
tests/integration
git diff --check
```
The complete suite passed with Ansible Core 2.21.3 and ansible-lint 26.8.0. It
covered default convergence, the selected source commit, executable version,
native configuration validation, clean repeats, missing-binary and checkout
rebuilds, metadata repair without rebuilding, nullable field rendering,
PromptKit source alternatives, intentional falsey values, caller-side
pipeline-map composition, dependency opt-out, and platform rejection. The
suite restored Notarius `v0.6.0` and the minimal `version: 4` configuration.
No additional production tasks, configuration probes, runtime validation,
private state, or unrequested hardening were found.
`git diff --check` also passed. No unresolved Feature 0003 findings remain.

View File

@@ -4,7 +4,7 @@ Last updated: 2026-09-08
Current milestone: MVP standalone application roles
Current focus: Remediate the Feature 0003 post-implementation review findings.
Current focus: Select the next work stream.
| ID | Deliverable | Owner | State | Evidence or next step |
| --- | --- | --- | --- | --- |
@@ -14,12 +14,12 @@ Current focus: Remediate the Feature 0003 post-implementation review findings.
| M0-04 | Aggregate repository status | workspace | done | `scripts/status` created |
| M0-05 | Suite-level role repository | ansible-role-dnd-pipeline | done | Repository created and added to `workspace.yml` |
| M1-01 | Remaining MVP design decisions | workspace | done | Feature 0003 roadmap fixes the Notarius configuration interface |
| M1-02 | Standalone application roles | role repositories | in_progress | Resolve the Feature 0003 remediation findings |
| M1-02 | Standalone application roles | role repositories | in_progress | Select the next standalone application role feature |
| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | proposed | Begin after standalone role interfaces stabilize |
| M1-04 | Collection assembly | ansible-collection-dnd | proposed | Select and implement the pipeline-role incorporation mechanism |
| F0001 | Install Seriatim from pinned source | ansible-role-seriatim | done | Implementation, integration coverage, and final remediation completed through `fb8dc41` |
| F0002 | Install and configure Audita | ansible-role-audita | done | Field-specific configuration completed in `e61f02f` and `847c4c3`; full suite passed |
| F0003 | Install and configure Notarius | ansible-role-notarius | in_progress | Resolve the findings in `docs/roadmap/remediation.md` |
| F0003 | Install and configure Notarius | ansible-role-notarius | done | Implemented and validated through remediation commit `eb4f511` |
## Updating This File