Skip to content

Give the manifest env() helper an injectable env seam (#484) - #501

Merged
leynos merged 9 commits into
mainfrom
issue-484-inject-env-seam-into-manifest-env-function
Aug 5, 2026
Merged

Give the manifest env() helper an injectable env seam (#484)#501
leynos merged 9 commits into
mainfrom
issue-484-inject-env-seam-into-manifest-env-function

Conversation

@leynos

@leynos leynos commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary

env_var — backing the env() Jinja helper — read the process environment directly:

fn env_var(name: &str) -> std::result::Result<String, Error> {
    match std::env::var(name) { ... }
}

Its three outcomes could only be reached by mutating global state, which the AGENTS.md testing mandate no longer permits. One was unreachable in practice regardless: fabricating a non-UTF-8 value in the live environment needs platform-specific OsString surgery, so the NotUnicode branch and its distinct Jinja error kind had no coverage at all.

The function's doc comment also advertised a test_support::env::VarGuard example that mutates global state; that goes with it.

Approach

Split resolution into env_var_with, taking a read_env closure — consistent with the existing seam in runner::process::ninja_program and the two added in #486 and #487. A closure rather than a trait object: keyed lookup, one caller, and the mandate permits a narrow closure where a trait object would be disproportionate.

Coverage

Six cases, none mutating anything:

  • a present variable resolves to its value
  • an empty value is returned rather than treated as missing — an empty value is a value, not an absence
  • both failures map to their documented Jinja error kind
  • the two failure kinds stay distinct — a missing variable is a template authoring error, whereas a non-UTF-8 value is an environment problem the author cannot fix in the template. Collapsing them onto one kind would misdirect whoever reads the failure, and nothing previously stopped that
  • the requested name reaches the seam unaltered and appears in the message

Checked against upstream RFCs

ortho-config RFC 0001 governs field-level environment aliases for configuration structs. It has no bearing on the manifest env() helper, which is Netsuke's own template surface, so the closure seam here is not in tension with the EnvSource abstraction being added upstream.

Verification

All gates pass: check-fmt, lint, typecheck, test (1194 nextest), markdownlint, nixie. CodeScene delta: no issues.

Closes #484.
Refs #496.

🤖 Generated with Claude Code

Summary by Sourcery

Introduce an injectable environment lookup seam for the manifest env() helper to enable full testing of all resolution outcomes without mutating process state.

Enhancements:

  • Add env_var_with helper that accepts a closure for environment variable resolution while preserving existing env_var behavior and error mapping semantics.

Tests:

  • Add dedicated env_function tests that cover successful resolution, empty values, distinct failure kinds, and propagation of variable names through error messages without touching the real environment.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Inject environment lookups into manifest env() evaluation through EnvReader.
  • Add manifest::from_str_with_env, process_env_reader, and env_var_with.
  • Retain process-environment defaults at public boundaries.
  • Preserve distinct error mappings for missing and non-UTF-8 values.
  • Add platform-independent tests without mutating process-global state.
  • Remove manifest_env_tests from the serial environment test group.
  • Update user, developer, and design documentation.
  • Replace the VarGuard example with a MockEnv example.
  • Add documentation coverage for from_str_with_env, EnvReader, and env('PROFILE').

Closes #484. References #496.

Verification

  • check-fmt
  • lint
  • typecheck
  • test — 1194 nextest tests
  • markdownlint
  • nixie
  • No CodeScene delta issues

Walkthrough

Use an injectable EnvReader for manifest Jinja lookups. Keep process-environment defaults for standard and file-based loading. Update tests, documentation, and serial-test configuration.

Changes

Manifest environment injection

Layer / File(s) Summary
Injectable environment helper and parser integration
src/manifest/env_reader.rs, src/manifest/mod.rs
Add EnvReader, process_env_reader, and from_str_with_env. Route Jinja env() lookups through the configured reader. Preserve Jinja error mappings.
Injected lookup tests
src/manifest/tests/*, tests/manifest_env_tests.rs
Test present, empty, missing, invalid UTF-8, special-character, and requested-name cases without changing process-global environment state.
Parallel environment test configuration and documentation
.config/nextest.toml, tests/makefile_test_target.rs, docs/developers-guide.md, docs/users-guide.md, docs/netsuke-design.md, tests/documentation_examples_tests.rs
Remove manifest_env_tests from serial-env. Document injected-reader ownership, execution rules, and the public API. Validate the documented example.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ManifestParser
  participant Jinja
  participant EnvReader
  Caller->>ManifestParser: Call from_str_with_env(yaml, reader)
  ManifestParser->>Jinja: Register env() with reader
  Jinja->>EnvReader: Request variable name
  EnvReader-->>Jinja: Return value or mapped error
  Jinja-->>Caller: Return parsed manifest or diagnostic
Loading

Possibly related issues

Possibly related PRs

  • leynos/netsuke#330 — Uses a related injected environment-reader pattern.
  • leynos/netsuke#473 — Updates the same serial environment test configuration and validation.
  • leynos/netsuke#515 — Directly overlaps the manifest reader, parser, and environment test changes.

Suggested labels: Issue

Suggested reviewers: codescene-access

Poem

Inject the reader; keep globals still.
Render manifests with deterministic skill.
Map missing names and invalid bytes.
Run manifest tests through parallel gates.
Keep process access at the boundary.

🚥 Pre-merge checks | ✅ 20
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the injectable manifest env() seam and links issue #484 as required.
Description check ✅ Passed The description directly explains the injectable environment seam, test coverage, documentation, and verification results.
Linked Issues check ✅ Passed The changes satisfy issue #484 by injecting EnvReader, preserving process defaults, removing environment mutation, and covering non-UTF-8 errors.
Out of Scope Changes check ✅ Passed The code, tests, configuration, and documentation changes support the linked issue objectives and contain no unrelated scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Testing (Overall) ✅ Passed Unit tests cover success, empty, missing, non-UTF-8, error kinds, and variable names; integration tests exercise injected readers through real manifest Jinja registration.
User-Facing Documentation ✅ Passed The users' guide documents the new EnvReader API, live-environment default, deterministic injection, error behaviour, and a concrete from_str_with_env example.
Developer Documentation ✅ Passed Accept the change: the developer's guide documents EnvReader ownership, call sites, composition, and test isolation; the design document records the injected env() boundary and defaults.
Module-Level Documentation ✅ Passed All touched Rust modules have //! documentation; env_reader explains its purpose, process-reader relationship, and composition rules, and test modules state their scope.
Testing (Unit And Behavioural) ✅ Passed Accept the check: unit tests cover present, empty, missing, non-UTF-8, error kinds, and names; behavioural tests exercise public from_str_with_env and rendered commands.
Testing (Property / Proof) ✅ Passed The change has a finite outcome mapping, not a range-based state or ordering invariant; tests cover Ok, empty, NotPresent, NotUnicode, error kinds, names, and integration wiring. No proof obligatio...
Testing (Compile-Time / Ui) ✅ Passed The change has no compile-time behaviour; its doctest and focused assertions cover runtime values, ErrorKind, names, and message fragments, so trybuild or snapshots are not required.
Unit Architecture ✅ Passed EnvReader is an explicit Result-returning seam; only process_env_reader calls std::env::var, and public parse boundaries inject it. Unit and integration tests avoid environment mutation.
Domain Architecture ✅ Passed from_str_with_env injects EnvReader; the sole std::env::var call is confined to process_env_reader, and tests exercise parsing without process mutation.
Observability ✅ Passed Retain the existing diagnostic path: missing and invalid-UTF-8 lookups expose distinct error kinds and the requested variable name; no service boundary or metric-worthy runtime behaviour was added.
Security And Privacy ✅ Passed The PR adds no credentials or secret literals; EnvReader returns values without logging them, and errors include only the requested name while discarding non-UTF-8 contents.
Performance And Resource Use ✅ Passed Accept the change: production paths create one EnvReader and clone one Arc per parse; lookups remain bounded by template use, with no new unbounded collection, loop, or repeated I/O.
Concurrency And State ✅ Passed EnvReader is caller-owned and Send + Sync; parsing clones it into a local Jinja environment, while migrated tests inject readers without global mutation or serialisation.
Architectural Complexity And Maintainability ✅ Passed Keep the change: EnvReader isolates one global lookup, supports both parse entry points and real registration tests, and has documented ownership without new dependencies or cycles.
Rust Compiler Lint Integrity ✅ Passed The PR adds no broad unused-code suppressions or artificial anchors; all new helpers and re-exports have real uses, and Arc/String clones serve callback ownership or repeated test results.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-484-inject-env-seam-into-manifest-env-function

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Injects an environment-reading seam into the manifest env() helper by introducing env_var_with, updating env_var to delegate through it, and adding focused tests that exercise all Jinja error paths without mutating the process environment.

Sequence diagram for manifest env() helper with injectable env seam

sequenceDiagram
    title Manifest env helper resolution via env_var_with

    actor TemplateAuthor
    participant Template as template
    participant EnvHelper as env
    participant EnvVar as env_var
    participant EnvVarWith as env_var_with
    participant ReadEnv as read_env_closure

    TemplateAuthor->>Template: render_manifest
    Template->>EnvHelper: env("FOO")
    EnvHelper->>EnvVar: env_var("FOO")
    EnvVar->>EnvVarWith: env_var_with("FOO", read_env_closure)
    EnvVarWith->>ReadEnv: read_env_closure("FOO")

    alt [value present]
        ReadEnv-->>EnvVarWith: Ok(String)
        EnvVarWith-->>EnvVar: Ok(String)
        EnvVar-->>EnvHelper: Ok(String)
        EnvHelper-->>Template: "FOO" value
    else [variable missing]
        ReadEnv-->>EnvVarWith: Err(VarError::NotPresent)
        EnvVarWith-->>EnvVar: Err(ErrorKind::UndefinedError)
        EnvVar-->>EnvHelper: Err(ErrorKind::UndefinedError)
    else [value not utf8]
        ReadEnv-->>EnvVarWith: Err(VarError::NotUnicode)
        EnvVarWith-->>EnvVar: Err(ErrorKind::TemplateRuntimeError)
        EnvVar-->>EnvHelper: Err(ErrorKind::TemplateRuntimeError)
    end
Loading

File-Level Changes

Change Details Files
Introduce an injectable environment seam for the manifest env() helper and adjust its documentation.
  • Add env_var helper that delegates to env_var_with using std::env::var
  • Extract env_var_with that takes a FnOnce(&str) closure returning Result<String, VarError> and maps outcomes to existing Jinja ErrorKind values
  • Update the doc comment example to use env_var_with instead of VarGuard and remove global environment mutation from documentation
src/manifest/mod.rs
Add targeted tests for env_var_with to cover success, empty, missing, and non-UTF-8 cases and ensure error kind distinctions and name propagation.
  • Create env_function test module for env() resolution behavior
  • Add tests verifying present and empty variable values are returned correctly
  • Add rstest-based parameterized tests that map VarError variants to the documented Jinja ErrorKind values
  • Add tests confirming the two failure kinds remain distinct and that the requested variable name is passed through to the seam and included in error messages
  • Wire the new env_function module into the manifest tests suite
src/manifest/tests/mod.rs
src/manifest/tests/env_function.rs

Assessment against linked issues

Issue Objective Addressed Explanation
#484 Introduce an injectable environment seam for the manifest env() helper, including removing direct std::env::var usage from src/manifest/mod.rs and supplying a mockable DefaultEnv at the manifest public boundary. The PR introduces env_var_with(name, read_env) and has env_var delegate to it via a closure, which does provide an injectable seam. However, env_var still calls std::env::var inside src/manifest/mod.rs via env_var_with(name,
#484 Rewrite the env_var documentation example to use a non-mutating mock/injected environment instead of test_support::env::VarGuard, eliminating in-process mutation.
#484 Migrate tests for the env() helper to the injected environment seam so they no longer mutate the process environment, and ensure the NotUnicode branch is covered by tests.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review August 2, 2026 07:14
@coderabbitai coderabbitai Bot added the Issue label Aug 2, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/manifest/mod.rs`:
- Around line 73-74: Update the manifest parsing flow around from_str and
env_var to accept a mockable::Env dependency, register env() with it, and
replace direct std::env::var access with the injected reader. Use
mockable::DefaultEnv in production and mockable::MockEnv in tests, preserving
existing environment lookup behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b0c043b2-8934-4085-9bd9-462f2dfcfd04

📥 Commits

Reviewing files that changed from the base of the PR and between 3f84545 and 48c1b8f.

📒 Files selected for processing (3)
  • src/manifest/mod.rs
  • src/manifest/tests/env_function.rs
  • src/manifest/tests/mod.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/rstest-bdd (auto-detected)
  • leynos/ortho-config (auto-detected)
  • leynos/shared-actions (auto-detected)

Comment thread src/manifest/mod.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48c1b8f7e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/manifest/mod.rs Outdated
Comment thread src/manifest/mod.rs Outdated
leynos pushed a commit that referenced this pull request Aug 2, 2026
Addresses the review findings on #501.

CodeRabbit and Codex both identified the same gap, correctly: the seam
reached only the leaf mapper, while `from_str_named` still registered the
hard-wired `env_var`. Tests of the actual Jinja registration therefore
still needed `VarGuard` and `serial_test`, so the PR claimed to remove a
mandate violation it had not removed.

`from_str_named` now takes an `EnvReader` — a shared `Fn(&str) ->
Result<String, VarError>`, `Send + Sync` because minijinja requires
registered functions to be — and the registered `env()` closure captures
it. `from_str` supplies `process_env_reader()`; `from_str_with_env` takes
one explicitly.

`tests/manifest_env_tests.rs` now drives the real registration path with
an injected reader. It is no longer `#[serial]` and no longer uses
`VarGuard`. The non-UTF-8 case drops its `OsStringExt` surgery and its
`#[cfg(unix)]` gate, so it runs everywhere.

Two consequences of the threading, each handled rather than suppressed:
`from_str_named` reached five arguments, so the three that travel
together are bundled into a `ManifestParse` struct; and `manifest::mod`
passed 400 lines, so the reader type, its process-backed default, and the
failure mapping move to `manifest::env_reader`.

Codex also asked for the helper's reuse policy to be recorded per
AGENTS.md; the developers' guide gains a "Manifest `env()` reader"
section covering ownership, permitted call sites, and composition.

Refs #484, #496.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/developers-guide.md`:
- Around line 541-546: The developer guide paragraph incorrectly retains
isolation requirements for manifest environment tests. Update the discussion
around the “Test isolation utilities” section to exclude
tests/manifest_env_tests.rs from EnvLock, EnvVarGuard, CwdGuard, and #[serial]
guidance, limiting those requirements to binaries that still mutate
process-global state or documenting a separate valid coverage exception.

In `@src/manifest/env_reader.rs`:
- Around line 27-33: Mark the Rust doctest fence in the process_env_reader
documentation as no_run, changing the existing rust fence to rust,no_run while
preserving the example content.
- Around line 46-50: Replace the stale [`env_var`] intra-doc link in the
surrounding documentation with plain text or a valid symbol reference, ensuring
rustdoc no longer attempts to resolve the removed helper while preserving the
description of the three outcomes tested by the helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 70a6ec0c-c5bc-46a7-9db9-b0e694c737da

📥 Commits

Reviewing files that changed from the base of the PR and between 3f84545 and d10fa0c.

📒 Files selected for processing (11)
  • docs/adr-006-adopt-polonius-nightly-toolchain.md
  • docs/developers-guide.md
  • docs/netsuke-design.md
  • docs/polonius.md
  • docs/snapshot-testing-in-netsuke-using-insta.md
  • docs/users-guide.md
  • src/manifest/env_reader.rs
  • src/manifest/mod.rs
  • src/manifest/tests/env_function.rs
  • src/manifest/tests/mod.rs
  • tests/manifest_env_tests.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/rstest-bdd (auto-detected)
  • leynos/ortho-config (auto-detected)
  • leynos/shared-actions (auto-detected)

Comment thread docs/developers-guide.md
Comment thread src/manifest/env_reader.rs Outdated
Comment thread src/manifest/env_reader.rs Outdated
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

docs/developers-guide.md (1)

837-839: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Restrict the ownership claim to production code.
tests/manifest_env_tests.rs constructs EnvReader directly with Arc::new. Therefore, “Nothing else constructs one except the public entry points” is too broad. State that production callers use the public entry points, while tests may construct injected readers directly.
Triage: [type:docstyle]

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/developers-guide.md around lines 837 - 839, Update the ownership
statement near manifest::from_str_named to scope it to production callers: say
production code uses the public entry points, while tests such as
manifest_env_tests.rs may construct injected EnvReader instances directly with
Arc::new.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/users-guide.md`:
- Around line 470-472: Remove the contributor-focused paragraph from the user
guide, including the reference to the developers' guide and the Manifest env()
reader section. Keep the surrounding user and embedding workflow documentation
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 10708772-63f0-4bd5-a2eb-6fb3aa945aa1

📥 Commits

Reviewing files that changed from the base of the PR and between 30cf9c9 and b2262b5.

📒 Files selected for processing (1)
  • docs/users-guide.md
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/rstest-bdd (auto-detected)
  • leynos/ortho-config (auto-detected)
  • leynos/whitaker (auto-detected)
  • leynos/shared-actions (auto-detected)

Comment thread docs/users-guide.md Outdated
leynos pushed a commit that referenced this pull request Aug 5, 2026
Round feedback on #501, each point verified against manifest/mod.rs.
The users' guide loses its contributor-facing pointer — that audience
is the developers' guide's, and the section must stay embedder-facing.
The developers' guide's ownership bullet claimed from_str_named owns
the reader; in fact the caller owns it, from_str_named borrows it via
ManifestParse and Arc::clones it into the registered closure, which
therefore co-owns the Arc. The design document's §4.4 bullet still
described env() as reading the system directly; it now names the
EnvReader boundary, the process-backed default, and the caller-supplied
alternative.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

tests/makefile_test_target.rs (1)

169-498: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Split the Rustflags contract tests into a sibling module.
Move the Rustflags helpers and tests into a dedicated module. Keep both Rust files

below 400 lines. Add a //! module comment to the new file.
As per coding guidelines, “No single Rust source file may exceed 400 lines.”

As per path instructions, “Files must not exceed 400 lines.”

Proposed module boundary
+#[path = "makefile_test_target/rustflags_contract.rs"]
+mod rustflags_contract;
+
-const RUSTFLAGS_PREFIX: &str = "RUSTFLAGS=\"";
-// Move the RustflagsCase helpers and Rustflags contract tests to the new module.
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @tests/makefile_test_target.rs around lines 169 - 498, Move the
Rustflags-specific constants, RustflagsCase, helper functions, and related tests
from the current test module into a sibling Rust module, preserving their
behavior and test coverage. Add a module-level //! documentation comment to the
new file, and ensure both the original file and the new module remain below 400
lines.

Sources: Coding guidelines, Path instructions, Learnings

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following failed checks now been resolved?

If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures.

Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. (Treat o11y, code safety, documentation and validation coverage as in scope).

Assessment against linked issues

Issue Objective Addressed Explanation
#484 Introduce an injectable environment seam for the manifest env() helper, including removing direct std::env::var usage from src/manifest/mod.rs and supplying a mockable DefaultEnv at the manifest public boundary. The PR introduces env_var_with(name, read_env) and has env_var delegate to it via a closure, which does provide an injectable seam. However, env_var still calls std::env::var inside src/manifest/mod.rs via env_var_with(name,

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

On the pre-merge table's Developer Documentation warning: that row predates dce4728, which already updated netsuke-design.md §4.4 (it now describes env() reading through the injected EnvReader, names process_env_reader() and from_str_with_env(), and states the caller-owns-the-reader model) and corrected the developers' guide's from_str_named ownership claim in the same commit. The refreshed table on the next round should reflect it.

Separately, the makefile_test_target decomposition requested against this PR now lives in #526, stacked on this branch, closing #524.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

leynos and others added 9 commits August 5, 2026 23:08
`env_var` read the process environment directly, so the `env()` Jinja
helper's three outcomes could only be exercised by mutating global
state. One was unreachable in practice: fabricating a non-UTF-8 value in
the live environment needs platform-specific OsString surgery, so the
NotUnicode branch and its distinct Jinja error kind had no coverage at
all. The AGENTS.md testing mandate now forbids the mutation regardless.

Split the resolution into `env_var_with`, taking a `read_env` closure,
consistent with the seams in runner::process::ninja_program and the two
added for #486 and #487. A closure rather than a trait object: this is a
keyed lookup with one caller, and the mandate permits a narrow closure
where a trait object would be disproportionate.

The stale doc example advertising a mutating `test_support::env::VarGuard`
goes with it.

Adds six cases, including that an empty value is returned rather than
treated as missing, and that the missing and non-UTF-8 failures keep
distinct error kinds — a missing variable is a template authoring error,
whereas a non-UTF-8 value is an environment problem the author cannot fix
in the template, and collapsing them would misdirect whoever reads the
failure.

Closes #484.
Refs #496.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Addresses the review findings on #501.

CodeRabbit and Codex both identified the same gap, correctly: the seam
reached only the leaf mapper, while `from_str_named` still registered the
hard-wired `env_var`. Tests of the actual Jinja registration therefore
still needed `VarGuard` and `serial_test`, so the PR claimed to remove a
mandate violation it had not removed.

`from_str_named` now takes an `EnvReader` — a shared `Fn(&str) ->
Result<String, VarError>`, `Send + Sync` because minijinja requires
registered functions to be — and the registered `env()` closure captures
it. `from_str` supplies `process_env_reader()`; `from_str_with_env` takes
one explicitly.

`tests/manifest_env_tests.rs` now drives the real registration path with
an injected reader. It is no longer `#[serial]` and no longer uses
`VarGuard`. The non-UTF-8 case drops its `OsStringExt` surgery and its
`#[cfg(unix)]` gate, so it runs everywhere.

Two consequences of the threading, each handled rather than suppressed:
`from_str_named` reached five arguments, so the three that travel
together are bundled into a `ManifestParse` struct; and `manifest::mod`
passed 400 lines, so the reader type, its process-backed default, and the
failure mapping move to `manifest::env_reader`.

Codex also asked for the helper's reuse policy to be recorded per
AGENTS.md; the developers' guide gains a "Manifest `env()` reader"
section covering ownership, permitted call sites, and composition.

Refs #484, #496.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CodeRabbit noted the developers' guide still required EnvLock and
`#[serial]` for manifest environment tests. The prose was stale, but so
was the configuration behind it.

`manifest_env_tests` was a member of the `serial-env` nextest group and
named in the guide as mutating process-global state. Since it moved to an
injected reader it mutates nothing, so it was being serialized for no
reason. Removed from `.config/nextest.toml`, from the guide, and from the
test that pins the group's membership.

That guard test now also asserts the binary stays *out*, so the
configuration cannot silently reacquire a constraint it no longer has.
The guide gains the general rule: a binary migrated to an injected seam
leaves the group and drops its `#[serial]` markers in the same change.

Also from the same review: the `process_env_reader` doctest is marked
`no_run`, since asserting a variable is absent makes the doctest a
hostage to whatever CI exports; and the intra-doc link to the removed
`env_var` is replaced.

Refs #484, #496.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CodeRabbit: the developers' guide claims `serial-env` covers exactly two
binaries, but the test only checked that the two expected ones appear and
that `manifest_env_tests` does not. A third could have joined unnoticed,
silently serializing tests that need not be, while the guide carried on
claiming otherwise.

The filter's members are now parsed and compared as a set, so the guide's
claim is enforced rather than weakened to "including". Verified by adding
a third binary, which fails and names the intruder:

    serial-env should cover exactly the two PATH- and NINJA_ENV-mutating
    binaries; found ["env_path_tests", "intruder_tests", "ninja_env_tests"]

This also subsumes the previous absence check: a binary that stops
mutating process state must leave the group, or the configuration
outlives the constraint it describes.

Also reverts markdown reflow that `make fmt` had carried into five
unrelated documents; #512 fixes that at the source.

Refs #484, #496.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The branch predated #512, which normalized the whole docs tree to the
mdtablefix 0.5.0 standard. Rebasing onto main therefore carried the
branch's older line wrapping and table padding back over five documents
the env-seam work never meant to touch.

Restore main's version of those five. Only docs/developers-guide.md
keeps a diff, and only for the sections this branch actually documents:
the serial-env group membership and the manifest env() reader seam.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The guide claimed nothing but the public entry points constructs an
`EnvReader`, and that tests must not reach past `from_str_with_env` to the
leaf mapper. Both are false. `tests/manifest_env_tests.rs` builds readers
with `Arc::new`, which is the point of the seam, and
`src/manifest/tests/env_function.rs` drives `env_var_with` directly.

Describe the split that actually exists, because the two layers cover
different things: integration tests exercise registration — that the reader
reaches the `env()` function Jinja calls — while unit tests cover error
mapping at the leaf, where the non-UTF-8 branch is reachable without
platform-specific `OsString` surgery.

Rename the section's `Composition rules` heading, which collided with the
one at line 503 under MD024. Discard the doctest's `Result` with `drop(...)`
rather than `let _ =`.

Addresses CodeRabbit findings on #501.
An accepted pre-merge item on #501: the guide named env()'s failure
behaviour but not the seam behind it, so embedders and test authors had
no user-facing pointer to from_str_with_env, EnvReader, or
process_env_reader. The new subsection states what the seam is for,
names the three entry points, and mirrors the executable doctest rather
than pretending the guide snippet is run by the YAML harness.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round feedback on #501, each point verified against manifest/mod.rs.
The users' guide loses its contributor-facing pointer — that audience
is the developers' guide's, and the section must stay embedder-facing.
The developers' guide's ownership bullet claimed from_str_named owns
the reader; in fact the caller owns it, from_str_named borrows it via
ManifestParse and Arc::clones it into the registered closure, which
therefore co-owns the Arc. The design document's §4.4 bullet still
described env() as reading the system directly; it now names the
EnvReader boundary, the process-backed default, and the caller-supplied
alternative.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI caught what the local docs gates could not: every fence in the
scanned guides must carry a tested-example marker, and the new
env-reader snippet had none, failing every documentation scenario at
load. The fence is now marked and registered, and a pin asserts the
snippet keeps naming the entry points it mirrors — from_str_with_env,
EnvReader, and the env('PROFILE') read — so the guide copy cannot
drift from the doctest silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@leynos
leynos force-pushed the issue-484-inject-env-seam-into-manifest-env-function branch from e0e1acd to 5446272 Compare August 5, 2026 21:15
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No quality gates enabled for this code.

@leynos
leynos merged commit d6841b5 into main Aug 5, 2026
17 checks passed
@leynos
leynos deleted the issue-484-inject-env-seam-into-manifest-env-function branch August 5, 2026 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inject an Env seam into the manifest env() Jinja function

3 participants