Skip to content

Cache config file layer discovery on startup (#319)#367

Draft
leynos wants to merge 1 commit into
issue-318-merge-pipeline-debug-loggingfrom
issue-319-cache-config-layer-discovery
Draft

Cache config file layer discovery on startup (#319)#367
leynos wants to merge 1 commit into
issue-318-merge-pipeline-debug-loggingfrom
issue-319-cache-config-layer-discovery

Conversation

@leynos

@leynos leynos commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #319

Eliminates the duplicate config-file I/O on startup: resolve_merged_diag_json and merge_with_config each independently discovered and loaded all file layers, so every config file was opened, read, and deserialised twice per run.

Stacked on #365 (merge-pipeline debug logging) because both touch merge.rs/discovery.rs/main.rs; this PR retargets to main automatically once #365 merges.

Changes

  • src/cli/discovery.rs: new ConfigFileLayers (discovery outcome loaded once; MergeLayer is Clone, so the merge clones cached layers instead of re-reading disk). push_file_layers now consumes the cache; collect_diag_file_layers is gone.
  • src/cli/diag.rs / src/cli/merge.rs: new resolve_merged_diag_json_with_layers and merge_with_config_layers; the original functions remain as thin self-loading wrappers, keeping the existing API for tests.
  • src/main.rs: loads the layers once and shares them between the pre-pass and the merge.
  • build.rs: verify_public_api_symbols entries for the new symbols (project convention for the build-script copy of the CLI modules).

Testing

  • New config_layers_are_loaded_once_and_shared test: loads the layers, deletes the config file, then verifies both the diag pre-pass and the merge still honour the file's contents — proving neither re-reads the disk.

Validation

  • make check-fmt / make lint / make test — pass (37 suites)

🤖 Generated with Claude Code

Summary by Sourcery

Cache configuration file layer discovery so diagnostic pre-pass and full merge share loaded config layers instead of re-reading from disk on startup.

Enhancements:

  • Introduce a ConfigFileLayers type to encapsulate discovered configuration layers for reuse across CLI operations.
  • Add layer-aware variants of diagnostic resolution and configuration merge functions while preserving the existing public API.
  • Wire main execution path to load config layers once and pass them to both diagnostic mode resolution and configuration merging.
  • Extend build-time public API symbol verification to cover the new config-layer types and functions.

Tests:

  • Add an integration test ensuring configuration layers are loaded once and reused even if the underlying config file is deleted after loading.

The startup path discovered and loaded configuration file layers
twice: once in `resolve_merged_diag_json` (the diagnostic-mode
pre-pass) and again in `merge_with_config` (the full merge), opening,
reading, and deserialising every config file twice per invocation.

Introduce `ConfigFileLayers`, loaded once per invocation, and
`_with_layers` variants of both consumers that share it. `main` now
loads the layers once and passes them to the pre-pass and the merge.
The original two functions remain as thin wrappers that load layers
themselves, preserving the existing API for tests and embedders.

The build script's `verify_public_api_symbols` gains entries for the
new public symbols, following the established convention that keeps
the shared modules warning-free when compiled into the build script.

A regression test proves the I/O is shared: it loads the layers,
deletes the config file, and verifies both the diag pre-pass and the
merge still honour the file's contents.
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d8610363-bee8-438f-b4f1-93bed6c8803b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-319-cache-config-layer-discovery

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

@sourcery-ai

sourcery-ai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Introduces a cached configuration file layer abstraction that is loaded once on startup and shared between the diagnostic pre-pass and full config merge, eliminating duplicate config-file I/O while preserving the existing public API surface.

Sequence diagram for cached config file layer reuse on startup

sequenceDiagram
    participant Run as run_with_args
    participant Layers as ConfigFileLayers
    participant Diag as resolve_merged_diag_json_with_layers
    participant MergeEntry as merge_cli_or_exit
    participant Merge as merge_with_config_layers
    participant Composer as MergeComposer

    Run->>Layers: ConfigFileLayers::load(parsed_cli)
    activate Layers
    Layers-->>Run: ConfigFileLayers
    deactivate Layers

    Run->>Diag: resolve_merged_diag_json_with_layers(parsed_cli, matches, &config_layers)
    activate Diag
    Diag->>Layers: ConfigFileLayers::as_result()
    Diag-->>Run: bool (DiagMode input)
    deactivate Diag

    Run->>MergeEntry: merge_cli_or_exit(parsed_cli, matches, mode, &config_layers)
    activate MergeEntry
    MergeEntry->>Merge: merge_with_config_layers(parsed_cli, matches, &config_layers)
    activate Merge
    Merge->>Composer: MergeComposer::with_capacity(4)
    Merge->>Merge: push_defaults_layer(composer, errors)
    Merge->>Merge: push_file_layers(&config_layers, composer, errors)
    Merge->>Composer: push_environment_layer(composer, errors)
    Merge->>Composer: push_cli_layer(cli, matches, composer, errors)
    Merge-->>MergeEntry: OrthoResult<Cli>
    deactivate Merge
    MergeEntry-->>Run: Result<Cli, ExitCode>
    deactivate MergeEntry
Loading

File-Level Changes

Change Details Files
Add ConfigFileLayers abstraction to discover and cache config file layers once per invocation, and refactor discovery to work over cached layers.
  • Introduce ConfigFileLayers wrapper around OrthoResult<Vec<MergeLayer<'static>>> with load and as_result helpers
  • Refactor push_file_layers to consume pre-loaded ConfigFileLayers instead of recomputing layers and to clone error Arcs when pushing to the error vector
  • Change push_discovered_layers to accept a slice of MergeLayer and clone each layer before pushing into the MergeComposer, avoiding ownership moves from the cached layers
  • Remove the now-redundant collect_diag_file_layers helper which separately loaded layers for diagnostics
src/cli/discovery.rs
Refactor diagnostic JSON resolution to operate on pre-loaded config layers while keeping a wrapper with the old signature for API compatibility.
  • Keep resolve_merged_diag_json as a thin wrapper that internally calls the new resolve_merged_diag_json_with_layers using freshly loaded ConfigFileLayers
  • Add resolve_merged_diag_json_with_layers that takes ConfigFileLayers and iterates over cached layers to determine diag_json, falling back to defaults when discovery fails
  • Change diag_json_from_file_layers to take ConfigFileLayers and return a bool directly, using as_result and cloning layers before into_value to preserve cached state
src/cli/diag.rs
Refactor config merge to reuse cached file layers and expose a new API that accepts them explicitly.
  • Keep merge_with_config as a thin wrapper that loads ConfigFileLayers and delegates to merge_with_config_layers
  • Add merge_with_config_layers that accepts pre-loaded ConfigFileLayers and uses push_file_layers(file_layers, ...) instead of recomputing file layers from Cli
  • Preserve existing merge sequencing (defaults, file, env, CLI) while changing only how file layers are obtained
src/cli/merge.rs
Wire the cached config layers through the main entrypoint so both diagnostic pre-pass and main merge share the same discovery result.
  • Load ConfigFileLayers once in run_with_args immediately after parsing CLI arguments
  • Use resolve_merged_diag_json_with_layers with the shared ConfigFileLayers when computing DiagMode
  • Pass the shared ConfigFileLayers into merge_cli_or_exit and call merge_with_config_layers there instead of merge_with_config
src/main.rs
Expose new symbols and validate them in the build script, and add a regression test proving layers are not reloaded from disk.
  • Re-export ConfigFileLayers and the *_with_layers variants from cli::mod so they are available to crate consumers
  • Extend verify_public_api_symbols in build.rs with size and function-signature checks for ConfigFileLayers, ConfigFileLayers::load, resolve_merged_diag_json_with_layers, and merge_with_config_layers
  • Add config_layers_are_loaded_once_and_shared test that loads config layers, deletes the backing file, and then asserts both diag resolution and merge still observe the original config values
src/cli/mod.rs
build.rs
tests/cli_tests/config_discovery.rs

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

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.

1 participant