Skip to content

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

Merged
leynos merged 35 commits into
mainfrom
issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup
Aug 23, 2026
Merged

Cache config file layer discovery (#319)#548
leynos merged 35 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 discovered configuration layers between diagnostic resolution and full configuration merging while preserving existing standalone callers and precedence behavior.

New Features:

  • Add a cached configuration discovery API that transfers discovered file layers from diagnostic resolution into the full merge.
  • Expose configuration discovery telemetry for pass outcomes and durations with bounded error categories.
  • Add public environment-provider support and compile-time coverage for external cached-configuration consumers.

Bug Fixes:

  • Prevent diagnostic resolution and subsequent configuration merging from repeating NETSUKE_CONFIG lookup and file-layer loading.
  • Preserve JSON selector precedence, merged configuration values, and deferred verbose diagnostics when using cached layers.
  • Avoid re-normalizing already discovered project-layer paths during project-scope checks.

Enhancements:

  • Refine configuration discovery and JSON-preference handling around retained discovery outcomes.
  • Extend observability recording to retain bounded discovery metrics alongside existing configuration-load metrics.

Build:

  • Add the CLI configuration API fixture directory to Dependabot coverage.

Documentation:

  • Document the cached configuration composition flow, discovery telemetry, environment-provider contract, and related migration guidance.
  • Update user documentation for discovery behavior and bounded configuration metrics.

Tests:

  • Add regression and property tests covering cached discovery reuse, single selector lookup, merge equivalence, selector precedence, diagnostics replay, and discovery telemetry.
  • Add an external compile-pass fixture for the public cached configuration API.

Chores:

  • Reorganize configuration discovery environment, JSON, and telemetry code into dedicated modules.
  • Update formatting and typo configuration for the changed documentation and identifiers.

@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 DiscoveryOutcome and DiscoveredLayers between diagnostic resolution and configuration merging.
  • Prevent repeated environment lookups, filesystem reads, and deserialisation for issue #319.
  • Preserve selector precedence, standalone callers, deferred diagnostics, merge behaviour, and project-scope handling.
  • Add bounded discovery telemetry, tracing, duration metrics, and public metric constants.
  • Add environment-provider seams, JSON helpers, path-normalisation handling, property tests, regression tests, API fixtures, and telemetry tests.
  • Update the developer, design, user, and migration documentation with the cached discovery model and observability boundaries.
  • Validate formatting, tests, lint, type checking, Markdown, and CodeRabbit review.

Walkthrough

Configuration discovery now uses injected environment access, cached outcomes, deferred diagnostics, normalised project matching, and timed telemetry. CLI merging reuses discovered layers. Tests and documentation cover the public API, precedence rules, metrics, and migration path.

Changes

Configuration discovery and observability

Layer / File(s) Summary
Discover and retain configuration layers
src/cli/discovery*.rs, src/cli/diag.rs, src/cli/merge.rs, src/config_load.rs
Discovery returns reusable outcomes, replays project-scope diagnostics, uses injected environment access, normalises project paths, and applies JSON precedence after discovery.
Record bounded discovery telemetry
src/cli/discovery_telemetry.rs, src/cli/mod.rs, src/observability*.rs, src/config_load_metrics_tests.rs
Timed discovery records bounded success or error metrics and duration samples. The recorder validates metric names, labels, and histogram shape.
Validate cached configuration hand-off
tests/cli_tests/*, tests/logging_stderr/config_tracing.rs, tests/command_env_ui_tests.rs, tests/ui/cli_configuration_pass/*, .github/dependabot.yml
Tests verify one environment lookup, cached layer reuse, diagnostic replay, JSON preference folding, merge equivalence, and compilation of the public cached configuration API.
Document the configuration API and related contracts
docs/developers-guide.md, docs/netsuke-design.md, docs/users-guide.md, docs/v0-1-0-migration-guide.md
Documentation describes cached discovery, injected environment access, deferred diagnostics, telemetry boundaries, API usage, execution contracts, and migration details.
Update spelling support
typos.toml, typos.local.toml
Spell-check configuration accepts MOLD and ignores NETSUKE_COLOR where required.

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant resolve_json_preference
  participant discover_file_layers_timed
  participant DiscoveryOutcome
  participant merge_with_config_and_env
  CLI->>resolve_json_preference: resolve diagnostic mode
  resolve_json_preference->>discover_file_layers_timed: discover configuration layers
  discover_file_layers_timed-->>DiscoveryOutcome: return layers and diagnostics
  resolve_json_preference-->>CLI: retain cached discovery outcome
  CLI->>merge_with_config_and_env: merge cached layers
  merge_with_config_and_env-->>CLI: return merged configuration
Loading

Suggested labels: Issue

Suggested reviewers: leynos

Poem

Layers wait once, then flow,
Diagnostics replay and show.
Metrics mark each timed flight,
Cached paths keep the merge light.
Tests guard the public way.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Unit Architecture ❌ Error merge_with_config_and_env is a public merge/query API, but the change instantiates StdMonotonicClock and invokes telemetry-emitting discovery without exposing that side effect. Move timing and telemetry to an explicit composition root; keep merge_with_config_and_env on a side-effect-free discovery path or inject an explicit observability dependency.
✅ Passed checks (19 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Accept the changes because they cache discovery for diagnostic and merge phases and add regression coverage as required by [#319].
Out of Scope Changes check ✅ Passed Accept the scope because telemetry, APIs, documentation, fixtures, and tests directly support cached discovery and its validation.
Docstring Coverage ✅ Passed Docstring coverage is 95.90% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 122 functions across 32 files. (4 skipped: 4 unsupported.)
Testing (Overall) ✅ Passed Accept: tests verify cached values after file mutation/removal, one selector lookup, injected merge values, JSON folding, path handling, diagnostic replay, and bounded discovery metrics and spans.
User-Facing Documentation ✅ Passed The users' guide documents cached discovery APIs, environment providers, reuse flow, telemetry names and labels, diagnostics, and unchanged CLI behaviour; the migration guide signposts the unstable...
Developer Documentation ✅ Passed Accept this check: the developer guide documents cached APIs, environment seams, telemetry, and bounded outcomes; the design and ADRs record the architecture, and related execplans are complete.
Module-Level Documentation ✅ Passed Pass: every PR-added Rust module has //! documentation, and affected modules describe purpose, function, and component relationships where needed.
Testing (Unit And Behavioural) ✅ Passed Retain the PR: public cached-handoff tests use real temporary files, property tests cover merge invariants, and binary tests cover success, failure, diagnostics, and metrics.
Testing (Property / Proof) ✅ Passed Mark PASS: the PR adds substantive proptest coverage for layer-order JSON folding, cached-versus-standalone merge equivalence, path normalisation, hashing, and diagnostic replay.
Testing (Compile-Time / Ui) ✅ Passed Accept this check: the PR adds external compile-pass coverage via Cargo check/direct rustc for the cached CLI API, plus focused redacted trace snapshots and semantic telemetry assertions.
Domain Architecture ✅ Passed Keep the change: discovery, environment, and telemetry stay under src/cli; EnvProvider and PathNormalizer isolate external access, while CliConfig remains outside the new infrastructure cou...
Observability ✅ Passed Approve: discovery records bounded success/error counters, duration, and a storage-boundary span; failure categories are closed, with no paths, selectors, or values in telemetry.
Security And Privacy ✅ Passed Pass: the diff adds only bounded discovery telemetry; spans use outcome/error_category, diagnostics hash paths, and environment values never enter logs, metrics, snapshots, or errors.
Performance And Resource Use ✅ Passed PASS: Keep the implementation; changed paths remain linear, normalize only the project key, reuse cached layers, and add fixed-cardinality telemetry. Tests cover one lookup and a 4,096-target bench...
Concurrency And State ✅ Passed Pass: DiscoveredLayers has per-call ownership, no shared cache or tasks are introduced, and telemetry uses a documented Once; local-recorder and concurrent-recorder tests cover state isolation and...
Architectural Complexity And Maintainability ✅ Passed The diff extracts existing discovery code and adds focused cache, environment, JSON, path, and telemetry seams; public consumers, tests, and documentation show immediate reuse with no new dependenc...
Rust Compiler Lint Integrity ✅ Passed The PR adds no broad unused-code suppressions or artificial anchors; new helpers and exports have callers, test modules use cfg(test), and added clones serve bounded test or snapshot ownership.
Title check ✅ Passed Pass because the title clearly describes cached configuration layer discovery and references issue #319.
Description check ✅ Passed Pass because the description directly explains the caching change, its objectives, validation, and linked issue.
✨ 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[bot]

This comment was marked as resolved.

@leynos
leynos force-pushed the issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup branch from 52bbe8a to 601eaee Compare August 22, 2026 02:30
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 22, 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.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

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

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

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.

Move discovery instrumentation to the startup composition boundary, where the
clock is injected, and preserve a regression test for the public merge API.

Consolidate the design guide's repeated Ninja synthesis material and relocate
unstable Rust composition guidance from the users' guide.
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 23, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

❌ Failed check (1 error)

Check name Status Explanation Resolution
Unit Architecture ❌ Error merge_with_config_and_env is a public merge/query API, but the change instantiates StdMonotonicClock and invokes telemetry-emitting discovery without exposing that side effect. Move timing and telemetry to an explicit composition root; keep merge_with_config_and_env on a side-effect-free discovery path or inject an explicit observability dependency.

@leynos

leynos commented Aug 23, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

docs/users-guide.md (1)

1170-1170: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the comma before because.
The clause because the wrapper cannot safely determine which jobs to wait for

gives the reason for rejection. The clause is essential, so do not separate it

with a comma.
Triage: [type:grammar]
As per path instructions, grammar findings require the Triage: annotation.

🤖 Detailed instructions

Use a wyvern agent team to verify each finding against the current code and only fix it if needed. Fix any documentation issues using a scribe agent team. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Use a scrutineer agent for execution of tests and summarizing the results.

In @docs/users-guide.md at line 1170, Remove the comma before “because” in the
sentence describing the nested eval payload, keeping the essential causal clause
directly connected to the preceding statement.

Sources: Path instructions, Linters/SAST tools

docs/developers-guide.md (1)

2389-2390: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Synchronize both discovery descriptions with the cached API.
The two documents still name removed discovery helpers. Use the current names so

the design and developer documentation describe one contract.

  • docs/developers-guide.md#L2389-L2390: replace

collect_diag_file_layers_with_sources with

collect_diag_file_layers_with_env.

  • docs/netsuke-design.md#L2777-L2780: replace

push_file_layers_with_sources with discover_file_layers and document the

DiscoveryOutcome hand-off.
As per coding guidelines, keep internal API documentation and design decisions

synchronized with the implementation.

🤖 Detailed instructions

Use a wyvern agent team to verify each finding against the current code and only fix it if needed. Fix any documentation issues using a scribe agent team. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Use a scrutineer agent for execution of tests and summarizing the results.

In @docs/developers-guide.md around lines 2389 - 2390, Synchronize both
documentation references with the current discovery API: in
docs/developers-guide.md lines 2389-2390, replace
collect_diag_file_layers_with_sources with collect_diag_file_layers_with_env; in
docs/netsuke-design.md lines 2777-2780, replace push_file_layers_with_sources
with discover_file_layers and document the DiscoveryOutcome hand-off.

Source: Coding guidelines

@coderabbitai

coderabbitai Bot commented Aug 23, 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 ---'
git rev-parse --short HEAD

printf '%s\n' '--- users guide: reported grammar passage ---'
sed -n '1158,1178p' docs/users-guide.md

printf '%s\n' '--- developers guide: reported discovery passage ---'
sed -n '2378,2400p' docs/developers-guide.md

printf '%s\n' '--- design guide: reported discovery passage ---'
sed -n '2765,2792p' docs/netsuke-design.md

printf '%s\n' '--- current and obsolete discovery API references ---'
rg -n -C3 \
  '\b(collect_diag_file_layers_with_sources|collect_diag_file_layers_with_env|push_file_layers_with_sources|discover_file_layers|DiscoveryOutcome)\b' \
  src docs tests

printf '%s\n' '--- discovery module outline ---'
ast-grep outline src/cli/discovery.rs --items all --view expanded

Length of output: 35196


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- nested-eval wording in users guide ---'
rg -n -i -C4 \
  'nested eval|cannot safely determine which jobs to wait for|because the wrapper' \
  docs/users-guide.md

printf '%s\n' '--- obsolete helper names in target guides ---'
rg -n -C2 \
  '\b(collect_diag_file_layers_with_sources|push_file_layers_with_sources)\b' \
  docs/users-guide.md docs/developers-guide.md docs/netsuke-design.md || true

printf '%s\n' '--- current helper names and DiscoveryOutcome hand-off in target guides ---'
rg -n -C2 \
  '\b(collect_diag_file_layers_with_env|discover_file_layers|DiscoveryOutcome|into_layers|merge_with_cached_file_layers)\b' \
  docs/developers-guide.md docs/netsuke-design.md

Length of output: 12400


@leynos — both findings are resolved at current revision d39e8f9.

  • docs/users-guide.md: The nested-eval sentence now reads: “makes the background-job count dynamic because the wrapper cannot safely determine which jobs to wait for.” It has no comma before because.

  • docs/developers-guide.md and docs/netsuke-design.md: Neither guide contains collect_diag_file_layers_with_sources or push_file_layers_with_sources. The developer guide documents discover_file_layers, DiscoveryOutcome, emit_diagnostics(), into_layers(), and merge_with_cached_file_layers. The design guide documents the same cached discovery flow and the DiscoveryOutcome hand-off.

The source matches the documentation. src/cli/discovery.rs defines collect_diag_file_layers_with_env, discover_file_layers, and DiscoveryOutcome. No further work or AI coding-agent prompt is required.

You are interacting with an AI system.

@leynos

leynos commented Aug 23, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

tests/logging_stderr/config_tracing.rs (1)

172-179: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Set the file error category.
Replace error_category: "io" with error_category: "file". The telemetry

classifier maps OrthoError::File to "file", so the current assertion fails

for the missing explicit configuration case.

🤖 Detailed instructions

Use a wyvern agent team to verify each finding against the current code and only fix it if needed. Fix any documentation issues using a scribe agent team. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Use a scrutineer agent for execution of tests and summarizing the results.

In @tests/logging_stderr/config_tracing.rs around lines 172 - 179, Update the
ConfigLoadFailureExpectation for the diag_mode_resolution operation in
assert_config_load_failure to use error_category "file" instead of "io",
matching the telemetry classifier’s OrthoError::File mapping.

@coderabbitai

coderabbitai Bot commented Aug 23, 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' '--- current revision and working tree ---'
git rev-parse --short HEAD
git status --short

printf '%s\n' '--- merge module outline ---'
ast-grep outline src/cli/merge.rs --items all --view expanded

printf '%s\n' '--- public merge API and discovery call path ---'
rg -n -A100 -B25 \
  'pub\s+fn\s+merge_with_config_and_env\b|fn\s+merge_with_config_and_env\b|discover_file_layers(?:_timed)?\b|StdMonotonicClock|record_discovery_outcome|timed_discovery' \
  src/cli/merge.rs src/cli/discovery.rs src/cli/discovery_telemetry.rs src/cli/mod.rs

printf '%s\n' '--- merge API callers and regression tests ---'
rg -n -A20 -B10 \
  '\bmerge_with_config_and_env\s*\(' \
  src tests benches

printf '%s\n' '--- PR diff for affected implementation ---'
base="$(git merge-base HEAD origin/main)"
git diff --unified=30 "$base" HEAD -- \
  src/cli/merge.rs src/cli/discovery.rs src/cli/discovery_telemetry.rs src/cli/mod.rs

Length of output: 58492


@leynossrc/cli/merge.rs: merge_with_config_and_env; src/cli/discovery.rs: discover_file_layers; src/cli/discovery_telemetry.rs: record_discovery_outcome

Mark the Unit Architecture check as resolved at current revision d39e8f9.

merge_with_config_and_env no longer instantiates StdMonotonicClock. It calls discover_file_layers, emits deferred diagnostics, and passes DiscoveredLayers to merge_with_cached_file_layers. The discovery path is side-effect-free with respect to telemetry.

record_discovery_outcome is now an explicit observability operation. Its caller supplies the MonotonicClock, start time, and DiscoveryOutcome. The regression test in tests/cli_tests/merge_diag.rs runs merge_with_config_and_env with a local metrics recorder and verifies that it emits no discovery telemetry. No further change is required.

You are interacting with an AI system.

@leynos

leynos commented Aug 23, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

docs/users-guide.md (1)

1170-1170: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the comma before because.
The clause because the wrapper cannot safely determine which jobs to wait for

gives the reason for rejection. The clause is essential, so do not separate it

with a comma.
Triage: [type:grammar]
As per path instructions, grammar findings require the Triage: annotation.

🤖 Detailed instructions

Use a wyvern agent team to verify each finding against the current code and only fix it if needed. Fix any documentation issues using a scribe agent team. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Use a scrutineer agent for execution of tests and summarizing the results.

In @docs/users-guide.md at line 1170, Remove the comma before “because” in the
sentence describing the nested eval payload, keeping the essential causal clause
directly connected to the preceding statement.

Sources: Path instructions, Linters/SAST tools

docs/developers-guide.md (1)

2389-2390: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Synchronize both discovery descriptions with the cached API.
The two documents still name removed discovery helpers. Use the current names so

the design and developer documentation describe one contract.

  • docs/developers-guide.md#L2389-L2390: replace

collect_diag_file_layers_with_sources with

collect_diag_file_layers_with_env.

  • docs/netsuke-design.md#L2777-L2780: replace

push_file_layers_with_sources with discover_file_layers and document the

DiscoveryOutcome hand-off.
As per coding guidelines, keep internal API documentation and design decisions

synchronized with the implementation.

🤖 Detailed instructions

Use a wyvern agent team to verify each finding against the current code and only fix it if needed. Fix any documentation issues using a scribe agent team. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Use a scrutineer agent for execution of tests and summarizing the results.

In @docs/developers-guide.md around lines 2389 - 2390, Synchronize both
documentation references with the current discovery API: in
docs/developers-guide.md lines 2389-2390, replace
collect_diag_file_layers_with_sources with collect_diag_file_layers_with_env; in
docs/netsuke-design.md lines 2777-2780, replace push_file_layers_with_sources
with discover_file_layers and document the DiscoveryOutcome hand-off.

Source: Coding guidelines

@coderabbitai

coderabbitai Bot commented Aug 23, 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' '--- target test module map ---'
ast-grep outline tests/logging_stderr/config_tracing.rs --items all --view expanded

printf '%s\n' '--- reported expectation and nearby failure assertions ---'
sed -n '140,195p' tests/logging_stderr/config_tracing.rs
rg -n -A30 -B12 \
  'ConfigLoadFailureExpectation|diag_mode_resolution|error_category|missing.*config|missing\.toml' \
  tests/logging_stderr/config_tracing.rs

printf '%s\n' '--- current discovery error classifier ---'
rg -n -A50 -B12 \
  'fn error_category\b|OrthoError::File|error_category' \
  src/cli/discovery_telemetry.rs src/cli src

printf '%s\n' '--- relevant tracing and test expectations ---'
rg -n -A24 -B10 \
  'diag_mode_resolution|configuration load failed|ConfigLoadFailureExpectation' \
  src tests

Length of output: 182814


@leynostests/logging_stderr/config_tracing.rs: explicit_load_failure_traces_failure_kind; src/config_load.rs: config_err_to_exit; src/observability.rs: classify_error

Withdraw this finding. I validated it against current revision d39e8f9.

Keep error_category: "io" in ConfigLoadFailureExpectation.

The finding conflates two different telemetry contracts:

  • src/cli/discovery_telemetry.rs::error_category maps OrthoError::File to "file" for the collect_diag_file_layers discovery span.
  • assert_config_load_failure checks the terminal configuration load failed event. src/config_load.rs::config_err_to_exit emits this event with observability::classify_error(err).
  • src/observability.rs::classify_error maps OrthoError::File to "io".

The test also excludes the terminal event from diagnostic_lines, then checks that terminal event separately. Changing the expectation to "file" would make the test incorrect. Do not make a code change. No AI coding-agent prompt is required.

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Aug 23, 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' '--- current revision and worktree ---'
git rev-parse --short HEAD
git status --short

printf '%s\n' '--- users guide: nested eval wording ---'
rg -n -i -C4 \
  'nested eval|cannot safely determine which jobs to wait for|because the wrapper' \
  docs/users-guide.md

printf '%s\n' '--- developers guide: reported discovery passage ---'
sed -n '2378,2400p' docs/developers-guide.md

printf '%s\n' '--- design guide: reported discovery passage ---'
sed -n '2765,2795p' docs/netsuke-design.md

printf '%s\n' '--- obsolete discovery names in documentation ---'
rg -n -C2 \
  '\b(collect_diag_file_layers_with_sources|push_file_layers_with_sources)\b' \
  docs || true

printf '%s\n' '--- current discovery API names and hand-off in docs and source ---'
rg -n -C2 \
  '\b(collect_diag_file_layers_with_env|discover_file_layers|DiscoveryOutcome|into_layers|merge_with_cached_file_layers)\b' \
  docs/developers-guide.md docs/netsuke-design.md src/cli/discovery.rs src/cli/merge.rs

Length of output: 19397


@leynos — mark both findings as resolved at current revision d39e8f9.

  • docs/users-guide.md: The nested-eval sentence has no comma before because. It reads: “makes the background-job count dynamic because the wrapper cannot safely determine which jobs to wait for.”

  • docs/developers-guide.md and docs/netsuke-design.md: Neither guide contains collect_diag_file_layers_with_sources or push_file_layers_with_sources. Both documents describe the current cached-discovery contract: discover_file_layers returns DiscoveryOutcome; the composition boundary calls emit_diagnostics(); into_layers() passes cached layers to merge_with_cached_file_layers.

Keep the current documentation. Do not make further changes. The only remaining push_file_layers_with_sources reference is in the historical execplan docs/execplans/adopt-ortho-config-v0-9-0.md. It records past implementation work and does not describe the active API.

You are interacting with an AI system.

Capture bounded discovery-span fields through the common test tracing
subscriber while preserving its event capture behaviour. This removes
duplicated test layers and keeps startup and telemetry checks aligned.
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos enabled auto-merge (squash) August 23, 2026 00:56
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 d091c0f into main Aug 23, 2026
17 checks passed
@leynos
leynos deleted the issue-319-cache-config-file-layer-discovery-to-avoid-double-i-o-on-startup branch August 23, 2026 01:06
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.

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

4 participants