Skip to content

Cache config file layer discovery (#319) - #548

Open
lodyai[bot] wants to merge 15 commits into
mainfrom
issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup
Open

Cache config file layer discovery (#319)#548
lodyai[bot] wants to merge 15 commits into
mainfrom
issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup

Conversation

@lodyai

@lodyai lodyai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch discovers file-backed configuration layers once during diagnostic
mode resolution and passes the loaded result to the full configuration merge.
It preserves standalone merge callers, selector precedence, and verbose
selector tracing without a second environment lookup or filesystem load.

The regression test drives the diagnostic and merge phases with one
mockable::MockEnv, requiring exactly one NETSUKE_CONFIG lookup while
confirming that configuration values remain merged.

Closes #319.

Validation

  • make check-fmt
  • make test (1,915 tests passed; 1 skipped; doctests passed)
  • make lint
  • make typecheck
  • coderabbit review --agent (0 findings)

References

Summary by Sourcery

Cache configuration file layer discovery so diagnostic JSON resolution and full configuration merge share a single environment-driven discovery pass.

New Features:

  • Introduce a DiscoveredLayers struct to hold discovered config file layers, associated errors, and selector resolution for reuse across diagnostic and merge phases.
  • Add APIs to resolve diagnostic JSON mode while returning the discovered file layers for subsequent merging.

Bug Fixes:

  • Ensure NETSUKE_CONFIG is only read once by reusing the cached discovery result between diagnostic and merge phases, preventing redundant environment lookups and file loads.

Enhancements:

  • Replace custom EnvProvider with the mockable crate’s Env/DefaultEnv interfaces across CLI discovery, diagnostics, merge logic, and tests.
  • Adjust discovery tracing to reuse cached selector resolution, preserving verbose trace output without repeating discovery.
  • Refine environment handling in merges to consume explicit environment maps via Env::all rather than custom entry collection.

Build:

  • Add the mockable crate as a build dependency to support environment mocking.

Tests:

  • Extend unit and integration tests to cover cached file layer reuse between diagnostic and merge phases, explicit config success/failure, discovery without selectors, and project-scope second-pass behaviour.
  • Update existing discovery, precedence, diagnostics, and BDD tests to use MockEnv-based helpers instead of the previous TestEnv environment double.

@coderabbitai

coderabbitai Bot commented Aug 9, 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

  • Cache file-backed configuration layer discovery between diagnostic resolution and full configuration merging.
  • Add DiscoveredLayers to retain loaded layers and deferred discovery errors.
  • Replay bounded discovery diagnostics and selector tracing without repeating environment lookup or filesystem loading.
  • Replace the custom environment provider with mockable::Env, DefaultEnv, and MockEnv.
  • Preserve selector precedence, standalone merge callers, explicit configuration errors, selector-free discovery, and project-scope behaviour.
  • Add public APIs for cached diagnostic resolution and layer-aware merging.
  • Add tests for cached discovery, single selector lookup, deferred diagnostics, load warnings, and public API integration, including issue #319 coverage.
  • Update configuration architecture documentation in docs/developers-guide.md and docs/netsuke-design.md.
  • Add mockable as a build dependency.

Walkthrough

The CLI now uses mockable::Env, caches configuration discovery, resolves diagnostic JSON mode from cached layers, replays deferred diagnostics, and passes the same layers into merging. Tests and public API fixtures use MockEnv.

Changes

Configuration discovery and merge reuse

Layer / File(s) Summary
Discover and retain configuration layers
Cargo.toml, src/cli/discovery*.rs, src/cli/discovery_layer_tests.rs, src/cli/discovery_tracing_tests.rs
Discovery retains layers, errors, bounded diagnostics, and project-scope trace state. Diagnostics replay without repeated environment or filesystem access. Tests cover explicit paths, empty discovery, project scope, precedence, and warning replay.
Resolve diagnostic mode from cached layers
src/cli/diag.rs, src/cli/config_path_precedence_tests.rs
JSON resolution uses injected environment access, derives values from discovered layers, reports discovery errors first, and returns the cached discovery result.
Merge retained layers into CLI configuration
src/cli/merge.rs, src/cli/main.rs, tests/bdd/helpers/config_environment.rs, tests/cli_tests/merge_diag.rs, tests/logging_stderr/config_tracing.rs
Startup passes discovered layers into merging. The merge combines file layers, raw process-environment entries, and CLI overrides. Tests verify layer reuse, non-Unicode environment handling, and cached tracing.
Expose and validate cached configuration APIs
src/cli/mod.rs, src/cli/test_support.rs, docs/developers-guide.md, docs/netsuke-design.md, tests/command_env_ui_tests.rs, tests/ui/cli_configuration_pass/*
Public exports use mockable::Env. Test helpers use MockEnv. Documentation and compile-pass tests cover cached discovery, diagnostic resolution, and layer-aware merging.

Sequence Diagram(s)

sequenceDiagram
  participant main
  participant resolve_json_and_layers_with_env
  participant discover_file_layers
  participant merge_with_layers
  main->>resolve_json_and_layers_with_env: resolve JSON mode and discover layers
  resolve_json_and_layers_with_env->>discover_file_layers: load configuration layers
  discover_file_layers-->>resolve_json_and_layers_with_env: return DiscoveryOutcome
  resolve_json_and_layers_with_env-->>main: return JSON mode and DiscoveredLayers
  main->>merge_with_layers: pass DiscoveredLayers
  merge_with_layers-->>main: return merged CLI configuration
Loading

Poem

Discover layers once.
Cache the paths and warnings.
Resolve JSON mode.
Merge the retained layers.
Let mocked environments test the flow.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 warning, 8 inconclusive)

Check name Status Explanation Resolution
User-Facing Documentation ⚠️ Warning The PR changes the public CLI API, but users-guide.md names none of the new APIs or removed ConfigEnvProvider aliases; the v0-1-0 migration guide is also unchanged for this break. Document the new cached configuration APIs and replacement environment seam in docs/users-guide.md, then add the breaking change to the v0-1-0 migration guide.
Testing (Overall) ❓ Inconclusive Investigating the changed behaviour and its tests before issuing the required assessment. Wait for repository evidence.
Developer Documentation ❓ Inconclusive Investigation started; repository evidence is still required before assessing documentation coverage. Inspect the pull-request diff, developer guide, design documents, and any roadmap or execplan files.
Testing (Property / Proof) ❓ Inconclusive Investigation started; no final assessment yet. Inspect the changed discovery, merge, and test code before deciding.
Unit Architecture ❓ Inconclusive Investigation is still in progress; no verdict has been reached. Continue reviewing the changed query, command, dependency, and diagnostic paths.
Domain Architecture ❓ Inconclusive The repository has no working-tree diff, so pull-request causality is not yet established; inspect the commit or base revision before deciding. Provide a usable pull-request diff or base revision, then verify whether the changed CLI discovery code violates the stated domain boundary.
Observability ❓ Inconclusive Investigation has not yet established whether the changed discovery behaviour has sufficient production observability. Inspect the pull-request diff and runtime telemetry before deciding.
Security And Privacy ❓ Inconclusive Initial repository state exposes no pull-request diff; inspect the current implementation before deciding whether a security or privacy failure was introduced. Provide a usable pull-request diff or base revision if the current tree cannot establish change causality.
Performance And Resource Use ❓ Inconclusive Investigation is still in progress; no verdict submitted yet. Continue code and diff analysis.
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes cached configuration layer discovery and references the linked issue number (#319).
Description check ✅ Passed The description directly explains cached discovery, layer reuse, diagnostic tracing, tests, and validation for the changeset.
Linked Issues check ✅ Passed The changes implement #319 by caching discovered layers, reusing them during merge, and adding regression coverage for reduced I/O.
Out of Scope Changes check ✅ Passed The environment, diagnostics, API, documentation, and test changes support cached discovery and its required integration, with no unrelated scope identified.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Module-Level Documentation ✅ Passed Accept the change: all 17 changed Rust module files carry //! documentation covering purpose, utility, and component relationships where needed.
Testing (Unit And Behavioural) ✅ Passed Tests cover success, missing-file errors, selector-free and project-scope cases; an integration test enforces one selector lookup and merged values, while stderr tests exercise the real binary boun...
Testing (Compile-Time / Ui) ✅ Passed Accept: the changed Rust API boundary has a Cargo compile-pass UI fixture, and focused insta snapshots cover selector and bounded load-warning schemas.
Concurrency And State ✅ Passed Pass: the diff adds no async tasks, locks, channels, or new global mutable state; DiscoveredLayers is privately owned and consumed, and tests verify one lookup plus cached replay.
Architectural Complexity And Maintainability ✅ Passed Assessment in progress; no verdict should be submitted yet.
Rust Compiler Lint Integrity ✅ Passed No explicit broad lint suppression or artificial unused-code anchor appears in the PR diff; only a narrow, reasoned disallowed-method expectation is added.
📋 Issue Planner

Built with CodeRabbit's Coding Plans for faster development and fewer bugs.

View plan used: #319

✨ 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-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup

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

@sourcery-ai

sourcery-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors CLI configuration discovery and merge to cache file-backed config layers discovered in a single pre-pass driven by a generic Env interface, then reuse those layers for diagnostics and full merge; replaces custom EnvProvider with mockable::Env/DefaultEnv, adjusts JSON/merge flows and tests to use the cached DiscoveredLayers and the mockable test helpers.

Sequence diagram for cached config layer discovery and merge

sequenceDiagram
    actor User
    participant Main as main_rs
    participant Diag as cli_diag
    participant Discovery as cli_discovery
    participant Merge as cli_merge
    participant Env as DefaultEnv

    User ->> Main: run_with_args
    Main ->> Diag: resolve_diag_mode_or_exit(parsed_cli, matches, fallback_mode)
    Diag ->> Diag: resolve_json_and_layers_with_env(cli, matches, Env)
    Diag ->> Discovery: collect_diag_file_layers_with_env(cli, Env)
    Discovery ->> Discovery: discover_file_layers(cli, Env)
    Discovery ->> Env: resolve_config_selector(cli.config, Env)
    Discovery -->> Diag: DiscoveredLayers
    Diag ->> Diag: json_from_layers(DiscoveredLayers.layers())
    Diag ->> Env: json_from_env(Env)
    Diag -->> Main: (DiagMode, DiscoveredLayers)

    Main ->> Discovery: DiscoveredLayers.replay_config_path_trace()
    Main ->> Merge: merge_cli_or_exit(parsed_cli, matches, DiagMode, DiscoveredLayers)
    Merge ->> Merge: merge_with_layers(cli, matches, Env, DiscoveredLayers)
    Merge ->> Discovery: push_discovered_file_layers(composer, errors, DiscoveredLayers)
    Merge ->> Env: Env.all()
    Merge ->> Merge: Figment::from(EnvironmentLayer::new(env_entries))
    Merge -->> Main: merged Cli
    Main -->> User: exit code / program outcome
Loading

File-Level Changes

Change Details Files
Introduce a cached configuration discovery result (DiscoveredLayers) and use it for both diagnostic JSON resolution and full configuration merge.
  • Add DiscoveredLayers struct to hold discovered file layers, associated errors, and the ConfigPathResolution used for tracing.
  • Implement discover_file_layers to perform one discovery pass using Env, returning DiscoveredLayers instead of raw layers or immediate errors.
  • Implement push_discovered_file_layers to add previously discovered layers and their errors into a MergeComposer, preserving existing error-accumulation semantics.
  • Change collect_file_layers_with_env to return (ConfigPathResolution, OrthoResult<Vec>) so resolution and outcome can be reused.
  • Update collect_diag_file_layers_with_env to return DiscoveredLayers instead of OrthoResult<Vec> and adjust callers/tests accordingly.
  • Expose methods on DiscoveredLayers for borrowing layers, accessing first_error, splitting into parts, and replaying config path trace without re-querying the environment.
src/cli/discovery.rs
src/cli/discovery_layer_tests.rs
src/cli/discovery_tracing_tests.rs
Replace the bespoke EnvProvider/StdEnvProvider with the mockable::Env/DefaultEnv abstraction and adapt discovery, diagnostic, merge, and test code to the new interface.
  • Remove EnvProvider trait and StdEnvProvider implementation; switch all discovery and diagnostic functions to accept &impl mockable::Env.
  • Use Env::os_string for individual lookups and Env::all for environment entries instead of EnvProvider::get/entries.
  • Update env_config_path and resolve_config_selector to operate on Env with os_string.
  • Change merge_with_config to use DefaultEnv and delegate to merge_with_layers with discovered file layers.
  • In merge_with_layers, build EnvironmentLayer from Env::all instead of env.entries().
  • Adjust CLI module exports to re-export DiscoveredLayers and the new resolve_json_and_layers_with_env and merge_with_layers functions instead of EnvProvider-related types.
src/cli/discovery.rs
src/cli/diag.rs
src/cli/merge.rs
src/cli/mod.rs
src/cli/discovery_layers.rs
src/main.rs
Cargo.toml
Update diagnostic JSON resolution to compute JSON mode and discovered layers together, then reuse those layers in the subsequent merge and tracing, eliminating duplicate discovery and environment lookups.
  • Add resolve_json_and_layers_with_env to compute JSON enabled flag and return DiscoveredLayers from the diagnostic discovery pass.
  • Refactor resolve_merged_json_with_env to call resolve_json_and_layers_with_env and discard the layers when only JSON mode is needed.
  • Change json_from_file_layers into json_from_layers, operating on a slice of MergeLayer without performing discovery itself.
  • Ensure discovery errors are surfaced immediately by resolve_json_and_layers_with_env using DiscoveredLayers::first_error.
  • Update json_from_env to work with Env::os_string instead of EnvProvider::get.
  • In main, replace resolve_json_mode_or_exit with resolve_diag_mode_or_exit that returns both DiagMode and DiscoveredLayers, replays config path trace after filters are set, and passes the cached layers into merge_cli_or_exit which now calls merge_with_layers.
src/cli/diag.rs
src/main.rs
Rework test support and tests to use mockable::MockEnv builders rather than custom TestEnv, and add coverage for the single-pass discovery and reuse of config layers between diagnostic and merge phases.
  • Replace TestEnv helper with mock_env_with and empty_mock_env that construct MockEnv instances with predefined os_string behaviour.
  • Adjust unit tests in discovery, discovery tracing, config path precedence, and diag modules to use empty_mock_env/mock_env_with and interact with Env/os_string instead of EnvProvider/get.
  • Add new tests in discovery_layer_tests.rs to validate discover_file_layers behaviour for explicit configs, missing configs, discovery without selectors, and project-scope second-pass discovery.
  • In merge_diag integration tests, replace the old TestEnv with MockEnv using expectation-based setup for os_string and add diag_and_merge_reuse_one_discovery_result test to assert that NETSUKE_CONFIG is looked up exactly once and that discovered layers are reused correctly by merge_with_layers.
  • Update BDD config_environment helper to build a MockEnv from TestWorld, wiring os_string and all to the world’s env_vars_forward, and use merge_with_config_and_env with this environment.
src/cli/test_support.rs
src/cli/discovery.rs
src/cli/discovery_layer_tests.rs
src/cli/discovery_tracing_tests.rs
src/cli/config_path_precedence_tests.rs
src/cli/diag.rs
tests/cli_tests/merge_diag.rs
tests/bdd/helpers/config_environment.rs

Assessment against linked issues

Issue Objective Addressed Explanation
#319 Introduce a cache of discovered configuration file layers so they are computed once and reused across startup phases.
#319 Ensure both diagnostic JSON resolution and the full configuration merge consume the same cached discovery result, avoiding redundant filesystem I/O and environment lookups.
#319 Add an automated check (test or benchmark) that demonstrates the reduction in duplicate discovery, such as enforcing a single environment lookup/config load across diagnostic and merge phases.

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 commented Aug 9, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

src/cli/discovery_layer_tests.rs

Comment on lines +201 to +219

fn discover_file_layers_records_an_explicit_load_error() -> Result<()> {
    let dir = tempdir().context("create temporary config directory")?;
    let cli = Cli {
        config: Some(dir.path().join("missing.toml")),
        ..Cli::default()
    };

    let discovered = discover_file_layers(&cli, &empty_mock_env());

    ensure!(
        discovered.layers().is_empty(),
        "a missing explicit config should not produce layers"
    );
    ensure!(
        discovered.errors.len() == 1,
        "a missing explicit config should record one error"
    );
    Ok(())
}

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: discover_file_layers_records_an_explicit_load_error,discover_file_layers_supports_discovery_without_a_selector

@coderabbitai

This comment was marked as resolved.

@leynos
leynos marked this pull request as ready for review August 9, 2026 14:04
codescene-access[bot]

This comment was marked as outdated.

@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.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai coderabbitai Bot added the Issue label Aug 9, 2026
coderabbitai[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@lodyai
lodyai Bot marked this pull request as draft August 9, 2026 15:06
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 9, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

tests/logging_stderr/config_tracing.rs

Comment on lines +136 to +139

    ensure!(
        joined.contains("resolved config path") && joined.contains("selector=\"cli_flag\""),
        "verbose stderr should replay the cached selector decision: {joined}"
    );

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: explicit_selection_traces_bounded_fields,invalid_config_traces_without_parser_text

@coderabbitai

This comment was marked as resolved.

@lodyai
lodyai Bot force-pushed the issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup branch from 79f2d41 to 7847192 Compare August 9, 2026 17:35
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 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
leynos marked this pull request as ready for review August 10, 2026 00:14

@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.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@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: 78471925eb

ℹ️ 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/cli/mod.rs Outdated
Comment thread src/cli/discovery.rs Outdated
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

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 and others added 15 commits August 15, 2026 21:03
Replace the bespoke config-selector environment trait with `mockable::Env`
so discovery and merging use the established injectable seam. Keep automatic
discovery from re-reading `NETSUKE_CONFIG` after that injected lookup, and
adapt deterministic unit, integration, and BDD coverage to `MockEnv`.
Discover file-backed configuration layers once during diagnostic resolution
and pass that result into the full merge. This preserves existing standalone
merge behaviour while removing repeated startup file loading.

Keep verbose selector tracing by replaying the cached decision after the
diagnostic output mode enables the tracing filter. Cover the shared flow with
a mock environment that permits one config-selector lookup only.
Keep non-Unicode configuration selectors and process environment entries in
their raw form so selection remains correct and environment-layer validation
can apply its documented policy without a startup panic.

Retain cached selector diagnostics through failed startup resolution, so
verbose users receive the same bounded context for configuration errors.
Document the current mockable environment APIs and cached discovery handoff while removing the retired provider interfaces.
Retain bounded selector, branch, and project-scope metadata while loading
configuration layers. Replay the original diagnostics after startup enables
verbose output without rereading the environment or filesystem.

Cover explicit and automatic replay paths, project-scope outcomes, and
verbose stderr output while preserving the existing bounded trace schema.
Replace retired environment-provider references with the current
`mockable::Env` boundary and describe the cached `DiscoveredLayers`
handoff used by startup.
Update the CLI architecture references for `DiscoveryOutcome`, its
`emit_diagnostics()` and `into_layers()` composition boundary, and the
production raw-environment merge handoff.
Describe the current cached discovery and deferred-diagnostics helpers,
and remove references to the retired direct file-layer push flow.
Keep discovery side-effect free by returning cached layers and bounded
diagnostics in `DiscoveryOutcome`. Emit the retained events only at the
startup or standalone merge composition boundary, so verbose output remains
complete without a second discovery pass.

Compile an external Cargo fixture against the public cached configuration API
and cover deferred tracing, load warnings, and selector-free branches.
Register the compile-pass fixture's Cargo manifest so dependency updates
continue to cover every checked-in Rust package and the manifest inventory
gate remains accurate.
Record a bounded counter at each full-merge boundary to distinguish reuse
of pre-discovered layers from standalone discovery. Keep paths, selectors,
errors, and configuration values out of metric labels.

Cover both outcomes with local recorders and document the telemetry
contract for future startup observability work.
Explain the unstable cached-discovery hand-offs, the replacement
environment seam, and standalone composition alternatives for API
callers.
Keep deferred configuration diagnostics to their correlation hash, presence,
selector, and failure-class fields so verbose output cannot disclose a raw
configuration file name.
Make the compile-pass fixture explicitly discard its `OrthoResult` values
without changing its cached-configuration flow or function-item binding.
Remove duplicate blank lines introduced while reconciling the migration and
configuration documentation during the rebase.
@leynos
leynos force-pushed the issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup branch from df3a87c to 926a27f Compare August 15, 2026 19:13
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.

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- revision and worktree ---'
git rev-parse --short HEAD
git status --short

printf '%s\n' '--- PR head and check state ---'
gh pr view 548 --repo leynos/netsuke \
  --json headRefOid,updatedAt,files,statusCheckRollup \
  --jq '{
    headRefOid,
    updatedAt,
    files: [.files[].path],
    checks: [.statusCheckRollup[] | {name, status, conclusion, workflowName}]
  }'

printf '%s\n' '--- affected documentation changed from main ---'
base="$(git merge-base HEAD origin/main)"
git diff --name-status "$base" HEAD -- \
  docs/users-guide.md \
  docs/v0-1-0-migration-guide.md

printf '%s\n' '--- documentation coverage ---'
for file in docs/users-guide.md docs/v0-1-0-migration-guide.md; do
  printf '%s\n' "--- $file ---"
  rg -n -C2 \
    'cached configuration discovery|discovered layers|ConfigEnvProvider|ConfigStdEnvProvider|mockable::(Env|DefaultEnv|MockEnv)|resolve_json_and_layers_(with_env|outcome_with_env)|merge_with_(layers|process_environment_layers|config|config_and_env)' \
    "$file" || true
done

printf '%s\n' '--- public CLI configuration exports ---'
sed -n '1,120p' src/cli/mod.rs

printf '%s\n' '--- relevant public declarations ---'
rg -n -A16 -B3 \
  'pub (fn|struct) (resolve_json_and_layers_with_env|resolve_json_and_layers_outcome_with_env|merge_with_layers|merge_with_process_environment_layers)|pub struct (DiscoveredLayers|DiscoveryOutcome)' \
  src/cli/diag.rs src/cli/discovery.rs src/cli/merge.rs || true

printf '%s\n' '--- documentation validation targets ---'
rg -n -C2 \
  'markdownlint|mdformat|prettier|^[[:space:]]*(fmt|format|markdownlint):' \
  Makefile justfile package.json .github 2>/dev/null || true

Length of output: 5551


🏁 Script executed:

#!/bin/bash
set -u

base="$(git merge-base HEAD origin/main)"

printf '%s\n' '--- documentation diff ---'
git diff --unified=3 "$base" HEAD -- \
  docs/users-guide.md \
  docs/v0-1-0-migration-guide.md || true

printf '%s\n' '--- users guide cached configuration section ---'
rg -n -i -A70 -B8 \
  'cached configuration discovery|ConfigEnvProvider|ConfigStdEnvProvider' \
  docs/users-guide.md || true

printf '%s\n' '--- migration guide cached configuration section ---'
rg -n -i -A100 -B8 \
  'cached cli configuration api|cached configuration discovery|ConfigEnvProvider|ConfigStdEnvProvider' \
  docs/v0-1-0-migration-guide.md || true

printf '%s\n' '--- current configuration exports ---'
sed -n '15,70p' src/cli/mod.rs || true

printf '%s\n' '--- resolution and merge signatures ---'
rg -n -A20 -B3 \
  'pub fn (resolve_json_and_layers_with_env|resolve_json_and_layers_outcome_with_env|merge_with_layers|merge_with_process_environment_layers|merge_with_config|merge_with_config_and_env)' \
  src/cli/diag.rs src/cli/merge.rs || true

exit 0

Length of output: 18830


@leynosdocs/users-guide.md; docs/v0-1-0-migration-guide.md; src/cli/mod.rs: resolve_json_and_layers_with_env, resolve_json_and_layers_outcome_with_env, DiscoveredLayers, DiscoveryOutcome, merge_with_layers, merge_with_process_environment_layers

Mark the User-Facing Documentation warning as resolved at revision 926a27f.

The users’ guide now documents cached configuration discovery, the required normal and diagnostic hand-offs, the mockable::Env environment seam, and the removed ConfigEnvProvider and ConfigStdEnvProvider aliases.

The v0.1.0 migration guide now classifies this as a breaking unstable Rust API change. It gives the migration flow and identifies merge_with_config and merge_with_config_and_env as standalone alternatives that do not reuse earlier discovery.

The current documentation matches the public exports and signatures in src/cli/mod.rs, src/cli/diag.rs, and src/cli/merge.rs. No further work or follow-up GitHub issue is required for this warning.


🧠 Learnings used
Learnt from: leynos
Repo: leynos/netsuke PR: 0
File: :0-0
Timestamp: 2026-08-14T22:57:52.249Z
Learning: For leynos/netsuke PR reviews, treat warnings as required work. When a finding is out of scope, identify an existing GitHub issue that covers it; otherwise propose a focused GitHub follow-up issue. Treat observability, code safety, documentation, and validation coverage as in scope.

Learnt from: leynos
Repo: leynos/netsuke PR: 0
File: :0-0
Timestamp: 2026-08-15T18:24:21.079Z
Learning: For leynos/netsuke PR reviews, user-facing documentation and migration-guide updates are required in the same PR when a public unstable Rust API changes or removes public aliases. Successful CI checks do not by themselves satisfy this documentation requirement.

Learnt from: CR
Repo: leynos/lille PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-08-15T15:34:49.965Z
Learning: Applies to docs/users-guide.md : New or changed user-facing functionality or behaviour must be clearly documented in the user's guide (`docs/users-guide.md`).

Learnt from: leynos
Repo: leynos/netsuke PR: 0
File: :0-0
Timestamp: 2026-08-15T19:14:57.999Z
Learning: In leynos/netsuke, user-facing documentation describes stable user contracts. Internally facing Rust API and implementation details belong in rustdoc and docs/developers-guide.md. Do not request docs/users-guide.md changes when the user-visible contract is unchanged.

You are interacting with an AI system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cache config file layer discovery to avoid double I/O on startup

2 participants