Files
narratio/docs/roadmap/implementation.md

12 KiB

Implementation Plan: Notarius Configuration Profile Selection

Status: Ready for implementation; all stages pending.

Scope and Working Instructions

Implement the feature roadmap, whose authority is the consumer request. Complete the numbered stages in order. Each stage is a bounded task for a gpt-5.6-terra coding agent. Do not treat completion of an intermediate stage as completion of the feature. Record completed stages and actual verification results here.

Before each stage, read docs/development.md, all documents under docs/policy/, the feature roadmap, and that stage's preparation list. Follow AGENTS.md discovery guidance. Use existing collaborators and fixtures; do not build a new configuration, cache, or profile-management subsystem. Tests must remain offline and independent of installed Notarius binaries and credentials. Do not change dependencies, implement Ansible changes, tag, or release as part of this plan.

Implementation Decisions

These choices resolve implementation details without adding restrictions to the feature request:

  • Represent the authored field as ConfigProfile *string with YAML/JSON name config_profile and omitempty, in both typed configuration and its safe YAML projection. Nil means omitted/null. A non-nil pointer preserves an explicitly supplied empty string as well as default and named selections.
  • Carry the same optional value in the Notarius adapter request. Nil emits no flag; non-nil emits --config-profile followed by the exact supplied string as a separate argument, including an empty string. Do not trim, lowercase, substitute Narratio's profile, impose a name regex, or inspect profile files. Notarius owns validation and selector interpretation.
  • For reuse evidence only, use one small stage-local helper that maps nil, "", and exact "default" to the empty identity; other values remain unchanged. Both extraction fingerprints use it. This does not mutate the authored field or change CLI forwarding. Do not attempt to recreate the downstream parser's complete normalization rules.
  • Add ConfigProfile string with json:"config_profile,omitempty" to both existing fingerprint payloads, populated only where extraction is enabled. Preserve existing field ordering and the current semantic fingerprint version (1). With no non-base selector the serialized payload remains unchanged; a named selection adds evidence that old records cannot already possess. No dual-reader, manifest migration, new durable metadata field, or broad fingerprint-version bump is needed. This is a minimal additive encoding, not a permanent promise to freeze fingerprint bytes across future releases.
  • Profile changes trigger the existing non-resumable/invalidation paths, not force mode. Preserve configured resume/cache controls, force precedence, credentials, output contracts, and stage-range behavior. Do not run extraction outside the operator's selected range or add a separate testing workspace.
  • Preserve the existing division of ownership: private downstream file changes behind an unchanged selector require operator-directed force when needed. No downstream configuration validation subprocess or runtime version gate is added.

Stage 1: Add Configuration and Adapter Support

Status: Pending.

Preparation:

  • docs/config.md (composition, profiles, Notarius, credentials).
  • docs/integrations/notarius.md (invocation and failure behavior).
  • internal/config/config.go, credential_projection.go, pipeline_configkit.go, pipeline_normalize.go, and notarius_test.go.
  • internal/adapters/notarius/runner.go, subprocess.go, fake.go, and subprocess_test.go.

Work:

  1. Add the optional field to NotariusConfig and the safeNotarius projection, including its returned value. Let existing ConfigKit composition handle overrides and null; do not add a default or resolve this name as a path.
  2. Add the optional field to notarius.RunRequest and append the argument pair when non-nil in SubprocessRunner.Run, before --json. Leave subprocess environment construction and error propagation unchanged.
  3. Audit any explicit Notarius configuration/request copies for the new field. Update actual omissions without introducing a generic cloning framework.
  4. Extend real configuration-load tests to cover a base selection, an overlay replacing it with a differently named downstream selection, and an overlay clearing it with null. Cover omitted, empty, and default values compactly. Verify the safe effective-YAML output retains a supplied value, including explicit empty, and round-trips without leaking credential values. Reuse existing credential tests rather than duplicating their full matrix.
  5. Extend adapter invocation tests for omitted and supplied selections, including empty and default. Assert the argument/value boundary rather than imposing new ordering requirements on unrelated arguments. Reuse the existing nonzero-exit test with a selected profile to prove there is no fallback or successful receipt processing after failure.

Verification:

go test ./internal/config ./internal/adapters/notarius

Completion: Configuration composition and safe inspection preserve the field, and the adapter forwards it correctly. The executing stage is connected in Stage 2 together with reuse tracking, so it cannot start using untracked profile selections as an intermediate implementation.

Stage 2: Wire Extraction and Profile-Sensitive Reuse

Status: Pending.

Preparation:

  • docs/internal/stage-extract.md.
  • internal/stage/extract.go, extract_resume.go, semantic_contracts_delivery.go, and their focused tests.
  • In particular, TestExtractStageResolvesManifestInputAndBuildsExactRequest, TestExtractSemanticConfigSensitivityAndOperationalExclusions, and TestExtractStageResumeValidationRequiresFreshEvidence.

Work:

  1. Pass cfg.ConfigProfile to the adapter request when extraction executes. Keep the field independent of credential forwarding and force overrides.
  2. Implement the reuse-identity helper and additive fingerprint fields described above. Update both extractSemanticConfig and fingerprintDocument, using the same identity in semantic comparison and extractionFingerprint. Keep disabled extraction insensitive to unused downstream settings.
  3. Extend the existing stage request test to prove the authored selection reaches the adapter. Cover ordinary and forced execution sufficiently to show that profile forwarding does not alter existing cache-control precedence.
  4. Extend semantic-sensitivity coverage: base to named, named to different named, and named to base change evidence; unchanged selection does not. Verify nil/empty/default share base evidence and disabled settings remain inert.
  5. Exercise the focused resume validator with an actual valid recorded bundle: it remains reusable for the same selection and becomes non-resumable for a changed selection. This guards the second fingerprint path independently of the application's semantic comparison.
  6. Check the additive encoding against the prior no-profile payload shape once in focused coverage or a recorded development check. Avoid whole-manifest snapshots and a permanent historical compatibility harness; retain existing input/output/reference sorting and all unrelated fingerprint fields.

Verification:

go test ./internal/stage ./internal/adapters/notarius ./internal/config

Completion: Selected profiles reach actual extraction, and both existing reuse checks account for the selection without forcing downstream cache refresh or changing the manifest schema.

Stage 3: Verify Application Lifecycle Behavior

Status: Pending.

Preparation:

  • internal/app/extract_lifecycle_test.go, runner_test.go, and run_control_test.go.
  • Existing fixtures and tests for changed extraction outcomes, failure/retry, and independent render/extract invalidation.

Work:

  1. Extend the existing lifecycle fixtures rather than building another harness. Run a successful extraction with a configured profile, then verify ordinary reuse for that same profile. Change only the downstream selection and verify that extraction executes again with the new value, upstream transcripts and render remain current, and succeeded dependents are invalidated/rerun through the existing runner policy. Include returning from a named selection to base.
  2. Cover the changed-profile failure boundary with the existing fake runner: return an ordinary downstream error and verify extraction is failed, the previous result is not advertised as current success, and dependents are not silently reused. Reuse existing retry coverage where it already proves the recovery behavior. Do not assert Notarius-specific diagnostic wording.
  3. Ensure one configuration-to-execution path proves explicit composition: Narratio's testing overlay can select a differently named Notarius overlay; without the field, selecting a Narratio profile does not populate the downstream request. Use real configuration loading and the existing injected runner, not a production provider or sibling repository dependency.
  4. Review existing operational-exclusion and force tests for continued validity. Do not broaden invalidation to the full effective configuration digest or Narratio's profile label, and do not automatically change cache options.

Verification:

go test ./internal/app ./internal/stage

Completion: Tests demonstrate the requested workflow, including selection changes and failure, across the real Narratio configuration/runner boundaries. Notarius's own overlay loader and cache internals remain outside these tests.

Stage 4: Document the Feature and Validate the Completed Change

Status: Pending.

Preparation: Canonical documentation owners listed in the feature roadmap, examples/README.md, and the existing development-focused operations guidance.

Work:

  1. Document the optional field in docs/config.md, including omitted/null, explicit base selectors, and independence from Narratio's profile and notarius.llm_api_key. Do not add profile-name restrictions.
  2. Update the invocation in docs/integrations/notarius.md to include the optional flag and identify Notarius v0.7.0 as a known supporting version, not an unconditional version requirement. Preserve the distinction from --llm-profile and ordinary downstream failure handling.
  3. Update docs/internal/stage-extract.md to describe selection-sensitive reuse and retain its distinction from private file content and operational settings. Make clear this is an explicit downstream setting, not blanket invalidation by Narratio's profile label or effective digest.
  4. Add concise development workflow guidance in docs/operations.md: explicit testing-overlay composition; different downstream names are allowed; switching selection triggers extraction when that stage is in scope; edits behind an unchanged selector may need force; testing is not a separate workspace. Preserve the existing distinction between extract+analyze and analyze-only regeneration.
  5. Update the maintained annotated pipeline example to show the optional field without requiring an externally installed testing overlay (use a commented named-selection example). Do not make previously runnable examples depend on new downstream files. Link to canonical owners instead of duplicating full contracts or adding new top-level Narratio flags.
  6. Review the final diff against every observable behavior and scope boundary in the consumer request. Mark the implementation stages and roadmap status accurately after verification; do not remove the original request or alter historical release notes.

Run the repository checks with the maintained Go 1.26 toolchain:

go test ./...
go test -race ./...
go vet ./...
go build ./...
go test ./internal/doccheck
go test ./internal/config -run '^TestExamplesLoadAndValidate$'
git diff --check

Completion: The requested interface, failure and reuse behavior, examples, and canonical documentation agree; all checks pass. No release is part of this implementation sprint.

Open Questions

None. The consumer request resolves the product behavior. The choices above settle implementation details without adding new operator restrictions, downstream configuration ownership, or cache guarantees.