Skip to content

Narrow the build script's module graph (#513) - #514

Merged
leynos merged 11 commits into
mainfrom
issue-513-narrow-build-script-module-graph
Aug 29, 2026
Merged

Narrow the build script's module graph (#513)#514
leynos merged 11 commits into
mainfrom
issue-513-narrow-build-script-module-graph

Conversation

@leynos

@leynos leynos commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes #513

Problem

build.rs recompiles part of the library so it can call cli::Cli::command()
for man-page generation. It declared src/cli/mod.rs, which pulled the whole
cli subtree — merging, discovery, diagnostics, localized value parsing — plus
cli_l10n, host_pattern, output_mode, and theme. Removing the five
module-wide #[expect(dead_code, ...)] attributes and building produced 110
unused-item diagnostics, which is what those attributes were suppressing.

The suppressions also masked genuinely dead code. Appending an unused
pub fn to src/cli/config.rs on main produced no diagnostic from any
compilation unit
: the library exports cli::config publicly so it is not
dead-code linted there, and the build script's module-wide expectation covered
it here.

Change

build.rs now declares an inline cli facade naming exactly the three files
the Clap schema needs, rather than inheriting the subtree:

#[path = "src/cli"]
mod cli {
    #[path = "config.rs"] pub mod config;
    #[path = "validation.rs"] mod validation;
    #[path = "command.rs"] mod command;

    pub use command::Cli;
    pub use config::{AccessibilityPolicy, ColourPolicy, EmojiPolicy, ProgressPolicy};
}

The library is split along the same seam so that slice is self-contained:

New module Contents Why it moved
src/cli/command.rs The Clap definitions (Cli, InteractionArgs, BuildArgs, GraphArgs, Commands) Was the top half of src/cli/parser.rs; the schema is all the man page needs
src/cli/preferences.rs The four Cli output-policy accessors theme_preference was the only reason the build script compiled theme and, transitively, output_mode
src/cli/validation.rs MAX_JOBS, validation_error Lets src/cli/config.rs stop reaching up into src/cli/mod.rs
src/host_matching.rs HostCandidate, HostPattern::matches The only items in src/host_pattern.rs the schema does not need

src/cli/parser.rs keeps the localization-aware parsing entry point;
cli_l10n, output_mode, and theme are no longer declared by the build
script at all.

Result

  • All five module-wide expectations removed. cargo check --all-targets
    emits no unused-item diagnostics.
  • The probe that was silent on main now reports: an unused pub fn in
    src/cli/config.rs produces
    warning: function ... is never used from the build-script crate.
  • The generated man page is byte-identical (verified by diffing the artefact
    before and after).
  • No dependency added, no public API change, nothing under locales/ or
    src/localization/ touched. The locale_catalogues/localization
    declarations were already correct and are untouched.
  • Rerun directives now track the modules actually compiled.
  • No file exceeds the 400-line cap (largest touched: src/cli/config.rs at
    321, src/host_pattern.rs down from 344 to 304).

docs/developers-guide.md gains a section recording the slice as a maintained
boundary: widening it reintroduces unreachable items, and a dependency added
outside it surfaces as a build-script compile error.

Gates

Gate Status
cargo fmt -- --check pass
make lint-clippy (cargo doc + clippy) pass
make test pass — 1312 nextest, 47 doctests
make markdownlint pass
make nixie pass

Two gates fail identically on unmodified origin/main in this environment and
are not caused by this change:

  • make check-fmt runs cargo fmt --all, which fails resolving the
    test_support path dependency's workspace. cargo fmt -- --check on the
    root package passes.
  • make lint's Whitaker pass reports no_std_fs_operations against
    build.rs and build_l10n_audit.rs — 9 findings on main, 8 after this
    change, all in std::fs calls this PR does not touch.

🤖 Generated with Claude Code

Summary by Sourcery

Narrow the build script's compiled module graph while separating CLI schema concerns and modernizing bounded event reporting at application boundaries.

New Features:

  • Add a maintained, narrowly scoped build-script module slice for generating CLI man pages and shell completions.
  • Expose cached merge events for application-side replay and add bounded network-policy decision tracing.
  • Support terminal-dot-insensitive host matching while preserving wildcard apex exclusion.

Bug Fixes:

  • Prevent build-script module-wide dead-code suppressions from masking genuinely unused library items.
  • Keep runtime-only CLI and host-matching code out of the build-script compilation graph.

Enhancements:

  • Split CLI command definitions, runtime preferences, validation, and host matching into focused modules.
  • Update CLI and configuration observability APIs so merge queries collect events without invoking observers or logging side effects.

Build:

  • Update build-script module declarations and rerun directives to track only the dependencies needed for generated CLI artefacts.

CI:

  • Add direct-rustc UI coverage that enforces the build-script module boundary and its supported dependency slice.

Documentation:

  • Document the maintained build-script module boundary and the updated cached-merge event replay API.
  • Clarify host matching and configuration observability behavior in user and design documentation.

Tests:

  • Add command-schema, build-module-slice, host-matching, and network-policy observability coverage.

Chores:

  • Remove the obsolete build-support module and adjust spelling configuration for repository terminology.

@coderabbitai

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

  • Narrow build.rs to the CLI modules required by cli::Cli::command().
  • Remove module-wide dead-code expectations and limit rerun directives to the compiled sources.
  • Split CLI command definitions, preferences, and validation into dedicated modules.
  • Move host-matching logic into host_matching.
  • Add command-schema, validation, host-matching, and build-slice boundary tests.
  • Document the maintained build-script module boundary in docs/developers-guide.md.
  • Align CLI structure documentation with docs/netsuke-design.md.

Validation

  • Preserve the public API, generated man pages, and dependency set.
  • Detect previously masked unused items.
  • Pass formatting, Clippy, tests, markdownlint, and Nixie gates.
  • Retain environment-specific failures in make check-fmt and make lint that also occur on origin/main.

Walkthrough

The PR separates CLI command, preference, and validation responsibilities, narrows build.rs compilation to a four-module slice, moves host matching into host_matching, and adds schema and module-boundary tests.

Changes

CLI command and validation

Layer / File(s) Summary
CLI command contract
src/cli/command.rs, src/cli/preferences.rs, src/cli/validation.rs, src/cli/mod.rs, src/cli/parser.rs, src/cli/config.rs, src/cli/parsing.rs, src/cli/diag.rs, src/cli/discovery.rs, src/cli/merge.rs, src/cli/merge_input.rs, src/cli/merge_observability.rs, src/cli/discovery_layers.rs, src/cli/discovery_helper_proptests.rs
Define CLI commands, arguments, defaults, preference accessors, and shared validation helpers in dedicated modules. Update CLI consumers and validation-reason mapping to use the new module paths.

Build-script module slice

Layer / File(s) Summary
Build-script module slice
build.rs, docs/developers-guide.md, tests/build_module_slice_ui_tests.rs, tests/ui/build_module_slice_*
Compile and track only the required config, validation, help, and command modules. Document and test the supported build-script module boundary.

Host matching

Layer / File(s) Summary
Host matching module
src/host_matching.rs, src/host_pattern.rs, src/lib.rs, src/stdlib/network/policy/mod.rs
Move exact and wildcard matching into host_matching. Keep parsing and normalisation in host_pattern, and update network policy imports.

CLI schema tests

Layer / File(s) Summary
CLI schema validation
tests/cli_tests/command_schema.rs, tests/cli_tests/mod.rs
Test default command selection and parsing for build, clean, graph, generate, and help commands.

CLI layout documentation

Layer / File(s) Summary
CLI module documentation
docs/netsuke-design.md
Document command.rs as the owner of Cli, with parsing in parser.rs and runtime preference accessors in preferences.rs.

Sequence Diagram(s)

sequenceDiagram
  participant BuildScript
  participant CliCommand
  participant CliConfig
  participant CliValidation
  BuildScript->>CliCommand: construct Cli command schema
  CliCommand->>CliConfig: resolve configuration types
  CliConfig->>CliValidation: apply validation policies
  CliCommand-->>BuildScript: return command data
  BuildScript->>BuildScript: generate man page
Loading

Suggested labels: Issue

Poem

Compile the narrow module slice.
Keep command ownership precise.
Route preferences through their home.
Match hosts in a dedicated dome.
Guard each boundary with tests.
Keep the build graph clean.

Merge Risk: 🟡 Moderate · up to 6b1c9

The PR narrows build-script compilation without changing the intended CLI schema, but merge observation still runs from a query path and can cause externally visible side effects for read-only callers; a platform-sensitive boundary test also needs hardening. Merge should wait for these bounded issues to be fixed or explicitly accepted.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error, 4 warnings)

Check name Status Explanation Resolution
Testing (Overall) ❌ Error The added tests substantially cover command parsing, host matching, validation, preference accessors, and the supported/unsupported build-module slice. However, the pull request also changes the obser… Add a focused build-script contract test for the exact rerun-if-changed paths. Refactor directive construction if required so the test can assert the emitted set, including the four compiled CLI files and src/host_pattern.rs, and exclud…
User-Facing Documentation ⚠️ Warning Fail: the PR introduces user-facing host-matching behaviour without updating docs/users-guide.md. src/host_matching.rs now removes one terminal DNS dot before matching. `src/stdlib/network/policy/… Update the “Configure network access” section in docs/users-guide.md. State that matching ignores one terminal DNS dot for exact and wildcard host patterns, and document the wildcard apex rule with examples such as example.com matching …
Testing (Unit And Behavioural) ⚠️ Warning The added tests cover the main behaviour: command parsing uses the public parser boundary, host matching has edge and property tests, validation has unit tests, and the build-slice fixture compiles pr… Normalize the contents read from build.rs to LF before find, contains, and path-count checks. Add a focused regression test for CRLF-normalized input where practical. Keep the strict module-boundary assertions and run the Windows test…
Testing (Compile-Time / Ui) ⚠️ Warning The PR adds a direct-rustc compile-pass and compile-fail UI test, which is the required language-specific equivalent. However, the new test is not portable to the supported Windows CI environment. `… Normalise build.rs line endings to LF before applying the source assertions, and add a focused regression test for CRLF input. Strengthen the source contract to compare or parse the complete inline cli facade, including module declarati…
Observability ⚠️ Warning Instrument the changed network-policy decision path. src/host_matching.rs now strips one terminal DNS dot before matching, while origin/main compared the raw candidate. NetworkPolicy::evaluate p… Either remove the terminal-dot normalisation if this behaviour is not intended, or add bounded observability at the fetch policy boundary. Emit a trace event for allowed and rejected evaluations with stable fields such as operation=fetch,…
✅ Passed checks (15 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes narrowing the build script's module graph and references the linked issue as required.
Description check ✅ Passed The description explains the problem, implementation, scope, test coverage, and gate results. It directly relates to the changeset.
Linked Issues check ✅ Passed The changes satisfy issue #513: build.rs uses a narrow CLI facade, retains Cli::command() man-page generation, adds no build dependency, removes broad dead-code expectations, updates rerun tracking, a…
Out of Scope Changes check ✅ Passed The module splits, host-matching extraction, documentation updates, and added tests support the narrow build-script boundary. No unrelated code changes are identified.
Docstring Coverage ✅ Passed Docstring coverage is 92.50% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 40 functions across 24 files. (2 skipped: 2…
Developer Documentation ✅ Passed Mark this check PASS. docs/developers-guide.md documents the exact four-file build.rs CLI slice, its purpose, excluded runtime modules, dependency-boundary behaviour, unused-item analysis, rerun i…
Module-Level Documentation ✅ Passed Pass the module-level documentation check. Every added or modified Rust module has a module docstring. The new command, preferences, validation, and host_matching modules explain their purpose…
Testing (Property / Proof) ✅ Passed Pass this check. The introduced hostname-matching rules use substantive proptest coverage for generated DNS labels, wildcard subdomain prefixes, ASCII case handling, and strict suffix or superdomain…
Unit Architecture ✅ Passed PASS: The pull request improves separation. The actual diff moves the Clap schema into cli::command, keeps localisation and fallible parsing in cli::parser, isolates runtime preference accessors i…
Domain Architecture ✅ Passed Keep the new boundaries. src/cli/command.rs contains the Clap schema, while parsing and runtime preference mapping remain in separate modules. src/host_pattern.rs now handles pattern validation, a…
Security And Privacy ✅ Passed PASS. The committed diff contains no secrets, credentials, tokens, certificates, or sensitive fixture data. The CLI types and serde derives were moved from parser.rs to command.rs; they do not a…
Performance And Resource Use ✅ Passed PASS. The pull request does not introduce a performance or resource-use failure. The production matching path remains a linear scan over the existing host-pattern lists, with one ASCII lowercase alloc…
Concurrency And State ✅ Passed Pass the check. The pull request narrows the build.rs module graph and splits CLI schema, preferences, validation, and host matching. The changed implementation adds no shared mutable state, locks, …
Architectural Complexity And Maintainability ✅ Passed Accept the change. The new command, validation, preferences, and host_matching modules each isolate an immediate dependency seam: build.rs compiles only the four-file CLI schema slice, `vali…
Rust Compiler Lint Integrity ✅ Passed PASS. The PR removes the five broad build-script #[expect(dead_code, ...)] suppressions and the obsolete build_support root. build.rs now compiles an explicit config, validation, help, and…
Full details: Linked Issues check

Explanation

The changes satisfy issue #513: build.rs uses a narrow CLI facade, retains Cli::command() man-page generation, adds no build dependency, removes broad dead-code expectations, updates rerun tracking, and adds boundary tests. The two reported gate failures are documented as pre-existing environment failures.

Full details: Docstring Coverage

Explanation

Docstring coverage is 92.50% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 40 functions across 24 files. (2 skipped: 2 unsupported.)

Full details: Testing (Overall)

Explanation

The added tests substantially cover command parsing, host matching, validation, preference accessors, and the supported/unsupported build-module slice. However, the pull request also changes the observable Cargo rerun contract in build.rs: emit_rerun_directives replaces src/cli/parser.rs and src/cli/parsing.rs with the four slice files and src/host_pattern.rs (build.rs lines 171-181). No test asserts this output. A plausible regression that retains the old rerun paths, or omits src/cli/validation.rs, would pass the current command, host, validation, and module-slice tests. The build-slice source check only examines the inline module declarations (tests/build_module_slice_ui_tests.rs lines 164-194), so it does not guard rerun behaviour. The same check also searches literal LF sequences and does not normalise CRLF line endings, which can make the boundary test fail on a valid Windows checkout.

Resolution

Add a focused build-script contract test for the exact rerun-if-changed paths. Refactor directive construction if required so the test can assert the emitted set, including the four compiled CLI files and src/host_pattern.rs, and excluding the removed parser/build-support paths. Normalise line endings before assert_fixture_matches_build_rs parses build.rs, and add a CRLF regression case if the test must run on Windows.

Full details: User-Facing Documentation

Explanation

Fail: the PR introduces user-facing host-matching behaviour without updating docs/users-guide.md. src/host_matching.rs now removes one terminal DNS dot before matching. src/stdlib/network/policy/mod.rs applies this matcher to allow and block host rules used by fetch(). The user's guide documents the host flags and wildcards, but it does not document the terminal-dot rule.

Resolution

Update the “Configure network access” section in docs/users-guide.md. State that matching ignores one terminal DNS dot for exact and wildcard host patterns, and document the wildcard apex rule with examples such as example.com matching example.com. and *.example.com matching sub.example.com. but not example.com..

Full details: Developer Documentation

Explanation

Mark this check PASS. docs/developers-guide.md documents the exact four-file build.rs CLI slice, its purpose, excluded runtime modules, dependency-boundary behaviour, unused-item analysis, rerun implications, and the direct-rustc fixtures. docs/netsuke-design.md records the CLI architecture split between command.rs, parser.rs, preferences.rs, and config.rs. No roadmap item or new execplan changed in this pull request. The only matching existing execplan is marked Status: COMPLETE and is historical. No translated developer guide exists, so locale synchronisation is not applicable.

Full details: Module-Level Documentation

Explanation

Pass the module-level documentation check. Every added or modified Rust module has a module docstring. The new command, preferences, validation, and host_matching modules explain their purpose and their relationships to the CLI, runtime, and build-script components. The inline cli modules in build.rs and the UI fixtures also have //! documentation. Existing module documentation was updated where the module responsibilities changed, including src/cli/mod.rs, src/cli/parser.rs, and src/host_pattern.rs.

Full details: Testing (Unit And Behavioural)

Explanation

The added tests cover the main behaviour: command parsing uses the public parser boundary, host matching has edge and property tests, validation has unit tests, and the build-slice fixture compiles production modules and rejects cli::discovery. However, tests/build_module_slice_ui_tests.rs:166-182 reads build.rs and searches only for LF sequences. The changed test therefore fails when the checked-out build.rs uses CRLF line endings. The repository runs the full test suite on windows-latest (.github/workflows/ci.yml:139-142,225-229), so this boundary test is not reliable on a supported platform.

Resolution

Normalize the contents read from build.rs to LF before find, contains, and path-count checks. Add a focused regression test for CRLF-normalized input where practical. Keep the strict module-boundary assertions and run the Windows test job.

Full details: Testing (Property / Proof)

Explanation

Pass this check. The introduced hostname-matching rules use substantive proptest coverage for generated DNS labels, wildcard subdomain prefixes, ASCII case handling, and strict suffix or superdomain rejection. The moved CLI preference mappings retain exhaustive domain and policy tests. The finite command schema and build-slice boundary use targeted schema and direct-rustc tests. No new lemma or proof assumption requires an exhaustive formal proof.

Full details: Testing (Compile-Time / Ui)

Explanation

The PR adds a direct-rustc compile-pass and compile-fail UI test, which is the required language-specific equivalent. However, the new test is not portable to the supported Windows CI environment. assert_fixture_matches_build_rs searches for LF-only strings at tests/build_module_slice_ui_tests.rs:168 and :182; a CRLF checkout makes the test fail before it compiles either fixture. The contributor description identifies this exact failure, but the final test code contains no line-ending normalization or CRLF regression coverage. The boundary assertion also counts only #[path] declarations, so an extra plain mod discovery; inside the production facade would not be detected.

Resolution

Normalise build.rs line endings to LF before applying the source assertions, and add a focused regression test for CRLF input. Strengthen the source contract to compare or parse the complete inline cli facade, including module declarations, so an unapproved runtime module cannot bypass the boundary check. Retain the focused diagnostic assertions rather than adding a broad, toolchain-sensitive compiler snapshot.

Full details: Unit Architecture

Explanation

PASS: The pull request improves separation. The actual diff moves the Clap schema into cli::command, keeps localisation and fallible parsing in cli::parser, isolates runtime preference accessors in cli::preferences, and moves host matching out of parsing-only host_pattern. The new accessors, default-command transformation, validation helper, and host matcher are pure or locally transforming operations. The build script retains its explicit file and environment boundaries, while its existing file writes remain visible in named build functions. The new command-schema and direct-rustc boundary tests exercise the declared seams. No changed production path hides I/O, network calls, clock access, global state, or other command-side effects behind a query API.

Full details: Domain Architecture

Explanation

Keep the new boundaries. src/cli/command.rs contains the Clap schema, while parsing and runtime preference mapping remain in separate modules. src/host_pattern.rs now handles pattern validation, and src/host_matching.rs contains pure matching logic. The network policy change only updates the import for that matching logic. The new PathBuf, Clap, Serde, and OrthoConfig usage stays in CLI adapter/configuration code, not in core domain code. No changed domain code introduces HTTP, SQL, persistence, filesystem, environment, or vendor-specific coupling.

Full details: Observability

Explanation

Instrument the changed network-policy decision path. src/host_matching.rs now strips one terminal DNS dot before matching, while origin/main compared the raw candidate. NetworkPolicy::evaluate passes url.host_str() to this matcher, so exact allowlist/blocklist decisions for dotted hosts can change. The fetch path only traces cache activity and remote request failures; policy evaluation and policy rejections have no log, trace, or metric signal. This violates the required observability for changed externally visible reliability behaviour.

Resolution

Either remove the terminal-dot normalisation if this behaviour is not intended, or add bounded observability at the fetch policy boundary. Emit a trace event for allowed and rejected evaluations with stable fields such as operation=fetch, decision, and a fixed violation category (scheme_not_allowed, missing_host, host_not_allowlisted, or host_blocked), without raw URLs or hosts. Add a bounded counter such as netsuke_network_policy_evaluations_total with only bounded outcome and reason labels. Add tests that capture the rejection event and counter, including the terminal-dot cases.

Full details: Security And Privacy

Explanation

PASS. The committed diff contains no secrets, credentials, tokens, certificates, or sensitive fixture data. The CLI types and serde derives were moved from parser.rs to command.rs; they do not add a new deserialization sink or privileged operation. The network-policy change only moves HostPattern::matches into host_matching.rs and normalizes one terminal DNS dot. Exact and wildcard boundaries remain enforced, including wildcard apex rejection and suffix rejection. build.rs continues to write only generated artefacts and uses Cargo-provided paths and metadata. The new direct-rustc tests use Cargo and rustc paths from the environment but do not print environment values or add runtime access. No new authentication, authorization, permission, network, or telemetry capability appears in the diff.

Full details: Performance And Resource Use

Explanation

PASS. The pull request does not introduce a performance or resource-use failure. The production matching path remains a linear scan over the existing host-pattern lists, with one ASCII lowercase allocation per candidate as before; the new terminal-dot check is constant-time. The CLI refactor moves schema and preference code without adding hot-path loops, retries, blocking I/O, caches, or unbounded collections. Build-script work is reduced by compiling a narrower module slice. New test loops and generated inputs have explicit small bounds, and the direct Cargo/rustc invocations run once for two fixed fixtures rather than in a runtime path.

Full details: Concurrency And State

Explanation

Pass the check. The pull request narrows the build.rs module graph and splits CLI schema, preferences, validation, and host matching. The changed implementation adds no shared mutable state, locks, async tasks, spawned workers, channels, atomic protocols, transactions, or ordering guarantees. The new Arc<OrthoError> only provides shared ownership of an immutable validation error, and the existing parser Arc<dyn Localizer> usage remains ordinary local ownership. No concurrency interleaving or lifetime test is required for these changes.

Full details: Architectural Complexity And Maintainability

Explanation

Accept the change. The new command, validation, preferences, and host_matching modules each isolate an immediate dependency seam: build.rs compiles only the four-file CLI schema slice, validation is shared by configuration and parsing, runtime preference accessors stay outside the build slice, and host matching stays outside host-pattern parsing. The direct-rustc fixtures and developer guide document and enforce this boundary. The dependency graph remains explicit and acyclic. The diff adds no generic traits, registries, frameworks, or third-party dependencies, and it removes the obsolete build_support composition root and module-wide dead-code expectations.

Full details: Rust Compiler Lint Integrity

Explanation

PASS. The PR removes the five broad build-script #[expect(dead_code, ...)] suppressions and the obsolete build_support root. build.rs now compiles an explicit config, validation, help, and command slice, while runtime-only CLI modules remain outside that boundary. The changed production files contain no new broad allow or expect attributes. The only new expectations are narrow, reasoned clippy::disallowed_methods expectations on test tool-path helpers. The only added .clone() preserves a small Vec<&str> for test diagnostics and is not excessive ownership work. New helpers and re-exports have real callers or test coverage; no artificial lint anchors were added to production code.

✨ 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-513-narrow-build-script-module-graph

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@sourcery-ai

sourcery-ai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors the CLI and host pattern modules to carve out a minimal, self-contained slice that the build script recompiles for man-page and localization audits, removing broad dead-code suppressions while keeping behavior and public API unchanged.

File-Level Changes

Change Details Files
Limit build.rs to a narrow, self-contained CLI and host-pattern slice instead of recompiling the full cli subtree.
  • Replace build.rs module import of src/cli/mod.rs with an inline cli facade that exposes only command, config, and validation modules and re-exports the needed types.
  • Stop declaring cli_l10n, output_mode, and theme in build.rs, and keep host_pattern and localization as separate modules.
  • Update build.rs rerun directives to track only the files actually compiled for man-page and localization generation.
build.rs
Split CLI schema, runtime preferences, and validation helpers into dedicated modules so the Clap schema is independent of parsing and runtime behavior.
  • Move Cli, InteractionArgs, BuildArgs, GraphArgs, and Commands from parser.rs into a new cli/command.rs, keeping only definitions and Clap derives there.
  • Introduce cli/preferences.rs to host Cli runtime preference accessors (theme_preference, accessibility_override, no_input, progress_enabled).
  • Introduce cli/validation.rs with MAX_JOBS and validation_error shared between parsing and config, and update config.rs and parsing.rs to depend on it.
  • Adjust cli/mod.rs to wire in the new submodules, re-export the public CLI surface from command.rs, and simplify parser re-exports.
  • Update merge.rs, diag.rs, discovery.rs, and parser.rs to import Cli and related types from command.rs and validation helpers from validation.rs.
src/cli/parser.rs
src/cli/command.rs
src/cli/preferences.rs
src/cli/validation.rs
src/cli/mod.rs
src/cli/merge.rs
src/cli/parsing.rs
src/cli/diag.rs
src/cli/discovery.rs
src/cli/config.rs
Separate host pattern syntax/normalization from hostname matching to keep build-script dependencies minimal while preserving behavior.
  • Remove HostCandidate and HostPattern::matches from host_pattern.rs, leaving only parsing, normalization, and related tests.
  • Add a new host_matching.rs module that defines HostCandidate and implements HostPattern::matches, including relocated wildcard/exact matching tests.
  • Update lib.rs to declare the new host_matching module and stdlib network policy code to use HostCandidate from host_matching instead of host_pattern.
  • Adjust host_pattern.rs tests and documentation comments to reflect its new focus on parsing and normalization only.
src/host_pattern.rs
src/host_matching.rs
src/lib.rs
src/stdlib/network/policy/mod.rs
Document the build script’s maintained module slice and the CLI schema split for future contributors.
  • Add a section to docs/developers-guide.md explaining the build.rs module slice, the rationale for keeping it narrow, and guidance on avoiding reintroduction of dead-code suppressions.
  • Update netsuke-design.md to describe the new locations of the Cli type, parsing entry point, and runtime preferences, consistent with the refactor.
docs/developers-guide.md
docs/netsuke-design.md

Assessment against linked issues

Issue Objective Addressed Explanation
#513 Narrow the build script's module graph (particularly around src/cli/ and related modules) so that module-wide #[expect(dead_code, unused_imports, ...)] attributes are no longer needed and unused items in src/cli/ once again produce diagnostics during a normal build.
#513 Preserve existing build-script behavior, especially the ability for build.rs to call cli::Cli::command() for man-page generation (and to use localization keys) without adding new build dependencies or breaking gates/tests.

Possibly linked issues


Tips and commands

Interacting with Sourcery

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

Customizing Your Experience

Access your dashboard to:

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

Getting Help

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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

@coderabbitai coderabbitai Bot added the Issue label Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

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

Inline comments:
In `@build.rs`:
- Around line 31-35: Update the boundary documentation in build.rs lines 31-35
to state that src/cli/command.rs contains command-schema and default-command
behavior, including Cli::with_default_command; do not move the method.
Synchronize the corresponding boundary statement in docs/developers-guide.md
lines 391-393 with the same wording and scope.

In `@docs/developers-guide.md`:
- Around line 382-384: Reconcile the build-script description in
docs/developers-guide.md with the generate_man_page call and the statement that
build.rs only performs localization auditing. Explicitly state whether build.rs
stages a man page or cargo-orthohelp is the sole generator, then update the
related maintenance guidance so it presents one consistent rule and preserves
docs/ as the source of truth.

In `@src/cli/command.rs`:
- Around line 117-124: Add Rustdoc usage and outcome examples for each affected
public/shared function: in src/cli/command.rs lines 117-124, document
with_default_command() selecting Commands::Build when command is None; in
src/cli/preferences.rs lines 14-44, document each policy-to-preference mapping
with examples; and in src/cli/validation.rs lines 15-20, describe the produced
OrthoError::Validation and show caller context.

In `@src/host_matching.rs`:
- Around line 21-23: Expand the documentation for HostPattern::matches with a #
Examples section demonstrating an exact host match, a wildcard subdomain match,
and rejection of the wildcard apex; show the expected boolean outcomes for each
case while preserving the existing implementation.
- Around line 23-35: Update HostPattern::matches to remove one trailing DNS dot
from the lowercased candidate hostname before applying exact or wildcard
matching. Preserve the existing wildcard subdomain-only behavior after
normalization, and add regression coverage for trailing-dot hosts against both
exact and wildcard patterns.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 74c58235-8cae-4681-8a68-6c1908f2098a

📥 Commits

Reviewing files that changed from the base of the PR and between 8e9c7cc and af77331.

📒 Files selected for processing (17)
  • build.rs
  • docs/developers-guide.md
  • docs/netsuke-design.md
  • src/cli/command.rs
  • src/cli/config.rs
  • src/cli/diag.rs
  • src/cli/discovery.rs
  • src/cli/merge.rs
  • src/cli/mod.rs
  • src/cli/parser.rs
  • src/cli/parsing.rs
  • src/cli/preferences.rs
  • src/cli/validation.rs
  • src/host_matching.rs
  • src/host_pattern.rs
  • src/lib.rs
  • src/stdlib/network/policy/mod.rs
🔗 Linked repositories identified

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

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

Comment thread build.rs Outdated
Comment thread docs/developers-guide.md
Comment thread src/cli/command.rs
Comment thread src/host_matching.rs
Comment thread src/host_matching.rs
@leynos
leynos marked this pull request as ready for review August 27, 2026 23:21

@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've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 2 days and 14 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@leynos
leynos force-pushed the issue-513-narrow-build-script-module-graph branch from af77331 to e9c8a02 Compare August 28, 2026 12:28
codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos force-pushed the issue-513-narrow-build-script-module-graph branch from e9c8a02 to 0c5157f Compare August 28, 2026 12:37
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

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.

@coderabbitai

This comment was marked as resolved.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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

coderabbitai[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos force-pushed the issue-513-narrow-build-script-module-graph branch from 0816a76 to a7992b1 Compare August 28, 2026 18:10
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.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos force-pushed the issue-513-narrow-build-script-module-graph branch from 8ae7d1c to 1997684 Compare August 28, 2026 23:30
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Head commit changed.

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.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

src/cli/merge.rs (1)

106-135: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Separate merge observation from the query path.
Return bounded merge events from this function. Invoke MergeObserver::observe from an application command adapter. The calls on Lines 122-134 let a caller-supplied observer mutate external state or persist logs during a merge query.
As per coding guidelines: “Query paths must not perform writes, mutate externally visible state, trigger network calls, emit irreversible side-effects”. As per path instructions: “Adhere to single responsibility and CQRS”.

🤖 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 @src/cli/merge.rs around lines 106 - 135, Update
merge_with_cached_file_layers_with_observer to collect and return bounded merge
events alongside the merged Cli instead of invoking MergeObserver::observe
during the merge query. Move observer invocation to the application command
adapter, preserving event ordering and existing merge/validation behavior while
keeping push_defaults_layer, push_discovered_file_layers,
push_environment_layer, push_cli_layer, and observe_validation_rejection free of
externally visible side effects in this query path.

Sources: Coding guidelines, Path instructions

@leynos

leynos commented Aug 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following failed checks now been resolved?

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

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

❌ Failed checks (1 error, 4 warnings)

Check name Status Explanation Resolution
Testing (Overall) ❌ Error The added tests substantially cover command parsing, host matching, validation, preference accessors, and the supported/unsupported build-module slice. However, the pull request also changes the obser… Add a focused build-script contract test for the exact rerun-if-changed paths. Refactor directive construction if required so the test can assert the emitted set, including the four compiled CLI files and src/host_pattern.rs, and exclud…
User-Facing Documentation ⚠️ Warning Fail: the PR introduces user-facing host-matching behaviour without updating docs/users-guide.md. src/host_matching.rs now removes one terminal DNS dot before matching. `src/stdlib/network/policy/… Update the “Configure network access” section in docs/users-guide.md. State that matching ignores one terminal DNS dot for exact and wildcard host patterns, and document the wildcard apex rule with examples such as example.com matching …
Testing (Unit And Behavioural) ⚠️ Warning The added tests cover the main behaviour: command parsing uses the public parser boundary, host matching has edge and property tests, validation has unit tests, and the build-slice fixture compiles pr… Normalize the contents read from build.rs to LF before find, contains, and path-count checks. Add a focused regression test for CRLF-normalized input where practical. Keep the strict module-boundary assertions and run the Windows test…
Testing (Compile-Time / Ui) ⚠️ Warning The PR adds a direct-rustc compile-pass and compile-fail UI test, which is the required language-specific equivalent. However, the new test is not portable to the supported Windows CI environment. `… Normalise build.rs line endings to LF before applying the source assertions, and add a focused regression test for CRLF input. Strengthen the source contract to compare or parse the complete inline cli facade, including module declarati…
Observability ⚠️ Warning Instrument the changed network-policy decision path. src/host_matching.rs now strips one terminal DNS dot before matching, while origin/main compared the raw candidate. NetworkPolicy::evaluate p… Either remove the terminal-dot normalisation if this behaviour is not intended, or add bounded observability at the fetch policy boundary. Emit a trace event for allowed and rejected evaluations with stable fields such as operation=fetch,…

@coderabbitai

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

echo '=== PR head and relevant changed files ==='
gh pr view 514 --repo leynos/netsuke --json headRefOid,updatedAt \
  --jq '{headRefOid, updatedAt}'
gh api --paginate 'repos/leynos/netsuke/pulls/514/files?per_page=100' \
  --jq '.[] | select(.filename | test("(^|/)(merge|merge_observability|merge_input|cli|developer).*\\.rs$|^docs/")) | [.status,.filename,.additions,.deletions] | `@tsv`'

echo '=== Repository guidance candidates ==='
fd -HI -t f . | rg '(^|/)(AGENTS|CONTRIBUTING|CODING|PATH.*INSTRUCTIONS|README)\.(md|txt)$|coderabbit.*ya?ml$' | while IFS= read -r f; do
  echo "--- $f"
  sed -n '1,240p' "$f"
done

echo '=== Source outlines ==='
for f in src/cli/merge.rs src/cli/merge_observability.rs src/cli/merge_input.rs; do
  if [ -f "$f" ]; then
    echo "--- $f"
    ast-grep outline "$f" --items all
  fi
done

echo '=== Merge implementation and observer interfaces ==='
rg -n -C 8 --glob '*.rs' \
  'trait\s+MergeObserver\b|struct\s+\w*Merge\w*Observer\b|enum\s+\w*Merge\w*Event\b|fn\s+merge_with_cached_file_layers_with_observer\b|\.observe\s*\(|observe_validation_rejection\b|push_(defaults|discovered_file|environment|cli)_layer\b' \
  src tests

echo '=== Call sites of the merge entry points ==='
rg -n -C 6 --glob '*.rs' \
  '\bmerge_with_cached_file_layers_with_observer\s*\(|\bmerge_with_cached_file_layers\s*\(' \
  src tests

echo '=== Relevant PR diff ==='
base=$(gh pr view 514 --repo leynos/netsuke --json baseRefName --jq .baseRefName)
git diff --unified=40 "origin/${base}...HEAD" -- \
  src/cli/merge.rs src/cli/merge_observability.rs src/cli/merge_input.rs tests docs || true

Length of output: 55610


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Application adapter replay ==='
nl -ba src/config_load.rs | sed -n '135,220p'

echo '=== Merge query and event collection ==='
nl -ba src/cli/merge.rs | sed -n '45,235p'

echo '=== Observer contract ==='
nl -ba src/cli/merge_observability.rs | sed -n '24,185p'

echo '=== Behavioural coverage for replay, ordering, and rejection ==='
ast-grep outline tests/cli_tests/merge_logging.rs --items all
rg -n -C 10 --glob '*.rs' \
  'MergeEvent|EventCollector|event.*order|order.*event|ValidationRejected|TracingMergeObserver|merge_and_capture|merge_with_cached_file_layers_with_observer' \
  tests/cli_tests/merge_logging.rs tests/ui/config_cached_discovery_embedder_pass.rs src/cli/merge.rs

echo '=== GitHub patch for merge-related PR files ==='
gh api --paginate 'repos/leynos/netsuke/pulls/514/files?per_page=100' \
  --jq '.[] | select(.filename == "src/cli/merge.rs" or .filename == "src/config_load.rs" or .filename == "src/cli/merge_observability.rs" or .filename == "tests/cli_tests/merge_logging.rs") | "FILE: \(.filename)\nPATCH:\n\(.patch // "<binary or omitted>")\n---"'

echo '=== Check status ==='
gh pr view 514 --repo leynos/netsuke --json statusCheckRollup \
  --jq '[.statusCheckRollup[] | {name, status, conclusion}]'

Length of output: 1680


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1"
  local start="$2"
  local end="$3"
  echo "=== ${file}:${start}-${end} ==="
  sed -n "${start},${end}p" "$file"
}

show_range src/config_load.rs 135 220
show_range src/cli/merge.rs 45 235
show_range src/cli/merge_observability.rs 24 185

echo '=== Merge logging test outline ==='
ast-grep outline tests/cli_tests/merge_logging.rs --items all

echo '=== Behavioural coverage for replay, ordering, and rejection ==='
rg -n -C 12 --glob '*.rs' \
  'MergeEvent|EventCollector|event.*order|order.*event|ValidationRejected|TracingMergeObserver|merge_and_capture|merge_with_cached_file_layers_with_observer' \
  tests/cli_tests/merge_logging.rs tests/ui/config_cached_discovery_embedder_pass.rs src/cli/merge.rs

echo '=== GitHub patch for merge-related PR files ==='
gh api --paginate 'repos/leynos/netsuke/pulls/514/files?per_page=100' \
  --jq '.[] | select(.filename == "src/cli/merge.rs" or .filename == "src/config_load.rs" or .filename == "src/cli/merge_observability.rs" or .filename == "tests/cli_tests/merge_logging.rs") | "FILE: \(.filename)\nPATCH:\n\(.patch // "<binary or omitted>")\n---"'

echo '=== Check status ==='
gh pr view 514 --repo leynos/netsuke --json statusCheckRollup \
  --jq '[.statusCheckRollup[] | {name, status, conclusion}]'

Length of output: 67633


@leynos Mark this finding as resolved.

src/cli/merge.rs::merge_with_cached_file_layers_with_observer() now returns:

(OrthoResult<Cli>, Vec<MergeEvent>)

The merge query does not accept a MergeObserver. It does not call MergeObserver::observe. The layer helpers collect bounded MergeEvent values only.

src/config_load.rs::merge_cli_or_exit() owns the application-side effect. It receives the completed merge result and event vector. It then replays each event through TracingMergeObserver in vector order before it handles the merge result.

The tests support this boundary:

  • tests/cli_tests/merge_logging.rs verifies the bounded event sequence and validation-rejection events.
  • tests/cli_tests/merge_logging.rs verifies that a merge query without observer replay emits no merge log events.
  • tests/ui/config_cached_discovery_embedder_pass.rs verifies that an external caller can collect events and replay them through its own observer.

The PR checks are successful, including build-test and build-test-windows.

You are interacting with an AI system.

@coderabbitai

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

echo '=== PR head and checks ==='
gh pr view 514 --repo leynos/netsuke \
  --json headRefOid,updatedAt,statusCheckRollup \
  --jq '{headRefOid,updatedAt,checks:[.statusCheckRollup[]|{name,status,conclusion,detailsUrl}]}' || true

echo '=== Changed files ==='
base=$(gh pr view 514 --repo leynos/netsuke --json baseRefName --jq '.baseRefName')
git diff --name-status "origin/${base}...HEAD"

echo '=== Relevant source outlines ==='
for f in build.rs tests/build_module_slice_ui_tests.rs src/host_matching.rs src/host_pattern.rs src/stdlib/network/policy/mod.rs docs/users-guide.md; do
  if [ -f "$f" ]; then
    echo "--- $f"
    ast-grep outline "$f" --items all 2>/dev/null || true
  fi
done

echo '=== Build rerun directives and their tests ==='
rg -n -C 5 --glob '*.rs' \
  'rerun-if-changed|rerun.*changed|generate_man_page|fn main\s*\(' \
  build.rs tests src || true

echo '=== UI assertion normalisation and regression coverage ==='
rg -n -C 5 --glob '*.rs' \
  'assert_fixture_matches_build|replace\("\\r\\n"|CRLF|crlf|widened.*boundary|discovery' \
  tests/build_module_slice_ui_tests.rs tests/ui || true

echo '=== Host matching and fetch-policy observability ==='
rg -n -C 5 --glob '*.rs' \
  'trim_end_matches|strip_suffix|terminal.*dot|HostCandidate|\.matches\(|NetworkPolicy::evaluate|fn evaluate|tracing::|trace!' \
  src/host_matching.rs src/host_pattern.rs src/stdlib/network/policy || true

echo '=== User documentation for network matching ==='
rg -n -C 5 \
  'Configure network access|host pattern|wildcard|terminal DNS|terminal.*dot|example\.com' \
  docs/users-guide.md || true

echo '=== Difference from origin/main for affected production files ==='
git diff --unified=25 "origin/${base}...HEAD" -- \
  build.rs src/host_matching.rs src/host_pattern.rs src/stdlib/network/policy/mod.rs docs/users-guide.md \
  tests/build_module_slice_ui_tests.rs || true

Length of output: 5779


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== PR file list ==='
gh api --paginate 'repos/leynos/netsuke/pulls/514/files?per_page=100' \
  --jq '.[] | [.filename, .status, .additions, .deletions] | `@tsv`'

echo '=== Current relevant sources ==='
for f in \
  build.rs \
  tests/build_module_slice_ui_tests.rs \
  src/host_matching.rs \
  src/host_pattern.rs \
  src/stdlib/network/policy/mod.rs \
  docs/users-guide.md
do
  echo "--- $f"
  nl -ba "$f" | sed -n '1,360p'
done

echo '=== Focused directive, UI, and observability references ==='
rg -n -C 8 --glob '*.rs' \
  'rerun-if-changed|rerun_directive|rerun.*path|assert_fixture_matches_build|build_module_slice_source|CRLF|crlf|NetworkPolicy|fn evaluate|trace!\s*\(|event!\s*\(|debug!\s*\(' \
  build.rs tests src || true

echo '=== Base-to-head GitHub patches for affected files ==='
gh api --paginate 'repos/leynos/netsuke/pulls/514/files?per_page=100' --jq \
  '.[] | select(.filename == "build.rs" or .filename == "tests/build_module_slice_ui_tests.rs" or .filename == "src/host_matching.rs" or .filename == "src/host_pattern.rs" or .filename == "src/stdlib/network/policy/mod.rs" or .filename == "docs/users-guide.md") | "FILE: \(.filename)\nPATCH:\n\(.patch // "<no textual patch>")\n---"'

Length of output: 3449


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show() {
  file="$1"
  echo "=== ${file} ==="
  sed -n '1,420p' "$file"
}

show build.rs
show tests/build_module_slice_ui_tests.rs
show src/host_matching.rs
show src/stdlib/network/mod.rs
show src/stdlib/network/observability_tests.rs
show docs/users-guide.md

echo '=== Relevant source and test matches ==='
rg -n -C 7 --glob '*.rs' \
  'rerun-if-changed|rerun.*changed|RERUN|assert_fixture_matches_build|replace\("\\r\\n"|CRLF|crlf|NetworkPolicy|fn evaluate|trace!\s*\(|event!\s*\(|debug!\s*\(|operation.?=.?fetch|allowed|rejected' \
  build.rs tests src || true

echo '=== PR patches for the affected findings ==='
gh api --paginate 'repos/leynos/netsuke/pulls/514/files?per_page=100' --jq \
  '.[] | select(.filename == "build.rs" or .filename == "tests/build_module_slice_ui_tests.rs" or .filename == "docs/users-guide.md" or .filename == "src/stdlib/network/mod.rs" or .filename == "src/stdlib/network/observability_tests.rs" or .filename == "src/host_matching.rs") | "FILE: \(.filename)\nPATCH:\n\(.patch // "<no textual patch>")\n---"'

Length of output: 148363


@leynos: Resolve all five findings. No further coding-agent prompt is required.

Check Status Evidence
Testing (Overall) Resolved tests/build_module_slice_ui_tests.rs::build_script_rerun_directives_match_the_compiled_module_slice asserts the exact CLI directive set: src/cli/command.rs, src/cli/config.rs, src/cli/help.rs, and src/cli/validation.rs. It requires exactly one src/host_pattern.rs directive. It rejects runtime-only paths, including src/cli/discovery.rs, src/cli/merge.rs, and src/host_matching.rs.
User-Facing Documentation Resolved docs/users-guide.md now states that exact and wildcard patterns ignore one terminal DNS dot. It gives exact and wildcard examples. It states that *.example.com does not match example.com..
Testing (Unit And Behavioural) Resolved The build-slice source parser normalizes \r\n to \n before it searches for the inline cli facade, validates module declarations, and counts path modules. fixture_contract_accepts_crlf_build_script_source exercises a CRLF version of the complete supported facade.
Testing (Compile-Time / UI) Resolved The UI test retains the direct-rustc production-module fixtures. The positive fixture must compile. The negative fixture must fail because the real inline slice does not declare cli::discovery. The test accepts stable unresolved-import diagnostic forms. The successful build-test-windows check confirms the portability repair works on Windows.
Observability Resolved src/stdlib/network/mod.rs emits a bounded tracing::debug! event at the fetch-policy boundary. Allowed decisions use operation="fetch" and policy_outcome="allowed". Rejected decisions also include a bounded policy_reason. src/stdlib/network/observability_tests.rs verifies both outcomes, verifies scheme_not_allowed, and verifies that raw URLs and hosts are not emitted.

The PR now addresses the reported validation, documentation, portability, UI-boundary, and observability requirements.

You are interacting with an AI system.

@leynos

leynos commented Aug 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

src/cli/merge.rs (1)

106-135: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Separate merge observation from the query path.
Return bounded merge events from this function. Invoke MergeObserver::observe from an application command adapter. The calls on Lines 122-134 let a caller-supplied observer mutate external state or persist logs during a merge query.
As per coding guidelines: “Query paths must not perform writes, mutate externally visible state, trigger network calls, emit irreversible side-effects”. As per path instructions: “Adhere to single responsibility and CQRS”.

🤖 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 @src/cli/merge.rs around lines 106 - 135, Update
merge_with_cached_file_layers_with_observer to collect and return bounded merge
events alongside the merged Cli instead of invoking MergeObserver::observe
during the merge query. Move observer invocation to the application command
adapter, preserving event ordering and existing merge/validation behavior while
keeping push_defaults_layer, push_discovered_file_layers,
push_environment_layer, push_cli_layer, and observe_validation_rejection free of
externally visible side effects in this query path.

Sources: Coding guidelines, Path instructions

@coderabbitai

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

echo '=== PR head and checks ==='
gh pr view 514 --repo leynos/netsuke --json headRefOid,statusCheckRollup \
  --jq '{headRefOid, checks: [.statusCheckRollup[] | {name, status, conclusion}]}' || true

echo '=== Relevant file map ==='
fd -HI -t f . src tests | rg '(^|/)(merge(\.rs|_observability\.rs|_logging\.rs)|config_load\.rs|config_cached_discovery_embedder_pass\.rs)$' || true

echo '=== Relevant source outlines ==='
for file in src/cli/merge.rs src/cli/merge_observability.rs src/config_load.rs tests/cli_tests/merge_logging.rs tests/ui/config_cached_discovery_embedder_pass.rs; do
  if [ -f "$file" ]; then
    echo "--- $file"
    ast-grep outline "$file" --items all 2>/dev/null || true
  fi
done

echo '=== Query, event, observer, and adapter evidence ==='
rg -n -C 10 --glob '*.rs' \
  '\bfn\s+merge_with_cached_file_layers_with_observer\b|\btrait\s+MergeObserver\b|\benum\s+MergeEvent\b|\bfn\s+merge_cli_or_exit\b|\.observe\s*\(|\bTracingMergeObserver\b|\bpush_(defaults_layer|discovered_file_layers|environment_layer|cli_layer)\b|\bobserve_validation_rejection\b' \
  src tests || true

echo '=== Relevant PR diff ==='
base="$(gh pr view 514 --repo leynos/netsuke --json baseRefName --jq '.baseRefName')"
git diff --unified=25 "origin/${base}...HEAD" -- \
  src/cli/merge.rs src/cli/merge_observability.rs src/config_load.rs \
  tests/cli_tests/merge_logging.rs tests/ui/config_cached_discovery_embedder_pass.rs || true

Length of output: 35871


@leynos Resolved.

src/cli/merge.rs now keeps the merge query free of observer side effects.

  • merge_with_cached_file_layers_with_observer() has no MergeObserver parameter.
  • The function returns (OrthoResult<Cli>, Vec<MergeEvent>) on Line 106.
  • The layer helpers append bounded MergeEvent values only.
  • The query does not call MergeObserver::observe.
  • Validation rejection adds a MergeEvent::ValidationRejected before the function returns the merge error.

src/config_load.rs::merge_cli_or_exit() now owns the application-side tracing action.

  • It calls the merge query.
  • It creates TracingMergeObserver.
  • It replays each returned event in vector order on Lines 189–193.
  • It handles the merge result after replay.

The test coverage supports this boundary.

  • tests/cli_tests/merge_logging.rs verifies event collection, ordering, rejection events, and no merge log events without replay.
  • tests/ui/config_cached_discovery_embedder_pass.rs verifies that an external caller can replay collected events through its own MergeObserver.

The current build-test and build-test-windows checks also report success.

You are interacting with an AI system.

leynos and others added 11 commits August 29, 2026 14:26
Compile only the schema slice required for `Cli::command()` in `build.rs`.
Keep parsing, preferences, validation, host matching, and runtime discovery
in sibling modules so build-script dead-code analysis remains meaningful.

Preserve the existing `help` command and CLI identity within the schema
slice, and document the four schema-only modules that the build script
compiles.
Protect the narrowed build-script CLI composition root with focused unit,
parser-schema, property, and direct-rustc UI tests.

Document the maintained UI boundary so later slice changes update its
positive and negative fixtures deliberately.
Bind the direct-rustc UI fixtures to the production CLI paths and verify
their declarations still match `build.rs`.

Keep the runtime-module rejection meaningful by compiling the same real
support graph in the positive and negative fixtures.
Restore the runtime CLI imports that the rebase lost while keeping the
four-file build-script slice narrow. Track the help schema file, retain
the UI boundary contract, and make command-schema coverage independent
per command variant.
Remove the obsolete `build_support` façade and align module and developer
documentation with the inline build-script slice. Normalize one terminal
DNS dot before policy matching while preserving wildcard apex rejection.
Accept CRLF checkouts before parsing the inline `build.rs` facade while
retaining the exact module declarations and count. Add a CRLF regression
alongside the direct-rustc boundary contract.
Keep cached configuration merging free of observer callbacks by returning
bounded events with the merge result and replaying them in `config_load`.
Update callers, documentation and the spelling policy to preserve the
established event order and required en-GB prose.
Assert that the static rerun directives match the narrow CLI facade and
exclude runtime-only modules. Document the terminal-DNS-dot matching rule
at the user-facing network-policy boundary.
Keep policy help metadata within the runtime parser while preserving the
four-file build-script facade. Retain direct-schema artefact coverage and
Clap-independent policy parsing.
Record bounded allowed and rejected decisions at the fetch boundary without
emitting raw URLs or hosts. Keep the network test module within its size
contract and correct the remaining build-slice prose.
Retain the main branch's observability example while preserving the
cached-merge API contract from this branch. Keep the documentation-test
identifier unique across the users' guide.
@leynos
leynos force-pushed the issue-513-narrow-build-script-module-graph branch from ae82581 to 60f4003 Compare August 29, 2026 12:35
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 c5fc483 into main Aug 29, 2026
18 checks passed
@leynos
leynos deleted the issue-513-narrow-build-script-module-graph branch August 29, 2026 21:20
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.

Narrow the build script's module graph instead of module-wide dead-code expectations

3 participants