Skip to content

Refine CLI output clarity with OrthoConfig localisation and tests#254

Merged
leynos merged 9 commits intomainfrom
terragon/refine-cli-output-clarity-cuftfl
Jan 4, 2026
Merged

Refine CLI output clarity with OrthoConfig localisation and tests#254
leynos merged 9 commits intomainfrom
terragon/refine-cli-output-clarity-cuftfl

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Jan 2, 2026

Summary

  • Refines CLI output clarity for users, adds localisation-backed messaging with English and Spanish catalogs, and expands tests around locale handling and CLI output.
  • OrthoConfig-backed layering for defaults, config files, environment variables, and CLI overrides with localisation-aware parsing; locale selection via --locale and NETSUKE_LOCALE.
  • Adds an ExecPlan doc (docs/execplans/cli-output-clarity.md) detailing plan for CLI output refinement, localisation, and testing; localization resources for CLI strings and errors; wiring for localization into CLI parsing; and tests to cover localized messages and precedence.
  • Adds localization resources under locales/en-US/messages.ftl and locales/es-ES/messages.ftl for CLI strings and error messages.

Changes

  • ExecPlan doc: docs/execplans/cli-output-clarity.md detailing plan for CLI output refinement, localisation, and testing.
  • Localization resources:
    • locales/en-US/messages.ftl
    • locales/es-ES/messages.ftl
  • CLI and localisation wiring:
    • New modules src/cli_localization.rs and updated src/cli.rs to derive OrthoConfig and localise clap output
    • build-time integration in src/main.rs to wire localisation and config merging into CLI parsing
    • src/lib.rs exports cli_localization for use across tests
  • Configuration and merging:
    • OrthoConfig integration for layered configuration (defaults, config files, env vars, CLI overrides)
    • Updated merge logic to support localisation-aware CLI parsing and merging via OrthoConfig types
  • CLI surface and localisation plumbing:
    • src/cli.rs updated to support locale-aware parsing, locale hints, and localisation hooks
    • build.rs and related code updated to accommodate locale-aware parsing hooks and cross-checks for localisation
  • Documentation updates:
    • docs/netsuke-design.md updated to reflect OrthoConfig-backed configuration and localisation wiring
    • docs/users-guide.md updated with configuration and localisation guidance
    • docs/roadmap.md updated accordingly
  • Build and dependency updates:
    • Cargo.toml include ortho_config and related features; include locales in package include
    • build.rs updates to support localised CLI parsing hooks and cross-checks for localisation
  • Tests:
    • Expanded tests (tests/cli_tests.rs) to cover locale handling, localisation of errors, and precedence of config layers
    • BDD tests updates for localisation scenarios in tests/features/cli.feature and tests/bdd/steps/cli.rs
  • Miscellaneous:
    • Minor wording tweaks in runner/process logging to reflect more precise actions and to improve consistency with localisation messaging

Rationale

Provides a robust, test-covered approach to localising CLI help, error messages and command output, while layering defaults, config files, environment variables, and CLI overrides via OrthoConfig. This helps ensure predictable behaviour across locales and easier testing.

Verification

  • Run cargo test to execute unit tests and behavioural tests (BDD steps) for CLI parsing and localisation.
  • Validate localisation on English and Spanish catalogs by running netsuke --help and invalid-subcommand scenarios.
  • Confirm configuration precedence via unit tests covering defaults, file, env, and CLI overrides.

Next steps

  • Apply OrthoConfig-backed CLI config for all commands and refine tests for edge-cases.
  • Extend Fluent catalog coverage and documentation with localisation notes.

🌿 Generated by Terry

📎 Task: https://www.terragonlabs.com/task/101b9946-a656-4e1c-8851-42910e061429

…larity

Introduce a new ExecPlan in docs/execplans/cli-output-clarity.md that outlines the purpose, progress checklist, decision log, and concrete steps for enhancing the Netsuke CLI output. This includes integrating OrthoConfig for configuration layering, localizing CLI help and error messages, refining user-facing messages, adding tests, and updating documentation to improve usability and consistency across CLI commands.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 2, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Summary by CodeRabbit

  • New Features

    • CLI localization with --locale (English + Spanish), config discovery and multi-layer merging, Network Policy options, Manifest command and --emit output.
  • Documentation

    • New ExecPlan for CLI output clarity, updated users guide with localization/configuration/network policy, and roadmap task marked complete.
  • Improvements

    • Clearer localized help/error messages, minor user-facing log text refinements, and expanded CLI tests for locale and merge behaviour.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Integrate Fluent-based CLI localisation, OrthoConfig-backed configuration discovery and layered merge, add English/Spanish locale resources, localiser builders and clap-localisation helpers, extend CLI parsing/merge flow, enable HostPattern (de)serialisation, update main entrypoint and tests, and add documentation and roadmap updates.

Changes

Cohort / File(s) Summary
Localization resources
locales/en-US/messages.ftl, locales/es-ES/messages.ftl
Add English and Spanish Fluent translations for CLI descriptions, subcommands and Clap error messages.
Localiser build & CLI localisation helpers
src/cli_localization.rs, src/cli_l10n.rs, src/lib.rs
Add localiser builders (English fallback, optional Spanish), layered Localizer, functions to localise clap Command and extract --locale hint; expose cli_localization module and crate-private cli_l10n.
CLI config, parsing & OrthoConfig
src/cli.rs, build.rs, src/main.rs
Add locale field, OrthoConfig/serde derives, localized parsing API parse_with_localizer_from, environment provider and config discovery, merge_with_config layered merge, new type alias in build.rs, and tracing initialisation in main.
Host pattern API & usage
src/host_pattern.rs, src/stdlib/network/policy/mod.rs
Implement FromStr/Serialize/Deserialize for HostPattern, introduce HostCandidate/ValidationContext types, adapt HostPattern::matches signature and use HostCandidate in network policy checks.
Cargo manifest & build deps
Cargo.toml, build.rs
Add ortho_config, serde, serde_json build-dependencies/features, include locales/** in package include, and wire new build.rs module imports.
Runner logs / messages
src/runner/mod.rs, src/runner/process/file_io.rs, src/runner/process/mod.rs
Reword user-facing log messages (Ninja invocation, file writing, command execution) without changing runtime control flow.
Documentation & roadmap
docs/execplans/cli-output-clarity.md, docs/users-guide.md, docs/netsuke-design.md, docs/roadmap.md
Add exec plan for CLI output clarity, document localisation and network policy options, record API signature notes in design doc, mark roadmap task complete.
Tests — CLI, locale & merge
tests/cli_tests/*, tests/bdd/steps/cli.rs, tests/features/cli.feature
Add locale hint parsing, Spanish error assertions, config-merge tests, BDD update for unknown-subcommand message; add OsString test helper and update test parsing logic to use localized parsing.
Test scaffolding & parsing changes
tests/cli_tests/mod.rs, tests/cli_tests/helpers.rs, tests/cli_tests/parsing.rs, tests/cli_tests/locale.rs, tests/cli_tests/merge.rs, tests/cli_tests/policy.rs
Add organised CLI test modules, os_args helper, update parsing tests for locale cases and invalid locale validation, add merge and policy-focused tests verifying precedence and network policy behaviour.

Sequence Diagram(s)

sequenceDiagram
    %% Styling note: keep palette subtle for accessibility
    participant OS as OS / Env
    participant Main as main()
    participant Localizer as build_localizer()
    participant Parser as parse_with_localizer_from()
    participant ConfigMerge as merge_with_config()
    participant Runner as runner::run()

    OS->>Main: argv (OsString[]) + env
    Main->>Main: collect args as OsString
    Main->>Main: extract locale hint from args
    Main->>Main: consult NETSUKE_LOCALE env
    Main->>Localizer: build_localizer(preferred_locale)
    Localizer-->>Main: Box<dyn Localizer>

    Main->>Parser: parse_with_localizer_from(args, localizer)
    Parser->>Parser: clap parse using Localizer (help/errors)
    Parser-->>Main: (Cli, ArgMatches)

    Main->>ConfigMerge: merge_with_config(&cli, &matches)
    ConfigMerge->>ConfigMerge: discover layers (defaults, file, env, CLI)
    ConfigMerge->>ConfigMerge: apply precedence & merge lists
    ConfigMerge-->>Main: merged Cli or error

    alt merge succeeds
        Main->>Main: init_tracing(merged_cli.verbose)
        Main->>Runner: runner::run(&merged_cli)
        Runner-->>Main: exit code
    else merge fails
        Main->>Main: init_tracing(ERROR)
        Main->>OS: log merge failure, exit FAILURE
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

Locales wake and verbs align,
Fluent keys in tidy line,
Layers stack and values blend,
Parsers, merges, tests attend,
Netsuke speaks — español and English fine.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and concisely summarises the main change: adding localization and tests for CLI output clarity via OrthoConfig.
Description check ✅ Passed The description thoroughly details the pull request's objectives, changes, and rationale; it clearly relates to the changeset and provides sufficient context.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch terragon/refine-cli-output-clarity-cuftfl

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63743d5 and 2872937.

📒 Files selected for processing (6)
  • Cargo.toml
  • build.rs
  • src/cli.rs
  • src/cli_l10n.rs
  • src/lib.rs
  • tests/cli_tests/merge.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • src/lib.rs
  • tests/cli_tests/merge.rs
  • build.rs
  • src/cli_l10n.rs
  • src/cli.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • src/lib.rs
  • tests/cli_tests/merge.rs
  • build.rs
  • src/cli_l10n.rs
  • src/cli.rs
Cargo.toml

📄 CodeRabbit inference engine (AGENTS.md)

Cargo.toml: In Rust Cargo.toml, use explicit version ranges and keep dependencies up-to-date.
All crate versions specified in Cargo.toml must use SemVer-compatible caret requirements (e.g., some-crate = "1.2.3") to allow safe non-breaking updates.
The use of wildcard (*) or open-ended inequality (>=) version requirements in Cargo.toml is strictly forbidden.
Tilde requirements (~) in Cargo.toml should only be used where a dependency must be locked to patch-level updates for a specific, documented reason.

Files:

  • Cargo.toml
🧠 Learnings (1)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • src/lib.rs
  • tests/cli_tests/merge.rs
  • build.rs
  • src/cli_l10n.rs
  • src/cli.rs
🧬 Code graph analysis (4)
tests/cli_tests/merge.rs (1)
src/cli.rs (2)
  • default (172-186)
  • merge_with_config (314-355)
build.rs (3)
src/cli_l10n.rs (1)
  • locale_hint_from_args (70-95)
src/cli.rs (2)
  • merge_with_config (314-355)
  • parse_with_localizer_from (237-254)
src/host_pattern.rs (2)
  • parse (176-182)
  • matches (184-196)
src/cli_l10n.rs (1)
src/cli.rs (1)
  • default (172-186)
src/cli.rs (2)
src/cli_l10n.rs (2)
  • locale_hint_from_args (70-95)
  • localize_command (14-40)
src/host_pattern.rs (2)
  • matches (184-196)
  • new (33-35)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: release / build-linux (aarch64-unknown-linux-gnu, linux-arm64, arm64) / Build linux artefacts
  • GitHub Check: release / build-macos (aarch64-apple-darwin, macos-15, macos-arm64, macos-aarch64) / Build macos artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: Sourcery review
  • GitHub Check: build-test (ubuntu-latest, stable)
  • GitHub Check: build-test (ubuntu-latest, nightly, true)
🔇 Additional comments (22)
src/lib.rs (1)

8-9: LGTM!

The module declarations correctly expose cli_localization publicly for test access while keeping cli_l10n as an internal implementation detail. This aligns with the PR's localization architecture.

Cargo.toml (4)

8-8: LGTM!

Including locales/** in the package ensures the Fluent translation catalogs are distributed with the crate, enabling runtime localization.


56-61: Build-dependencies are correctly configured.

The additions of ortho_config, serde, and serde_json to build-dependencies support the localized CLI parsing and man page generation in build.rs.


5-5: Rust 1.89.0 has been released (4 August 2025) and is a valid minimum supported Rust version for this project.


54-54: ortho_config version 0.7.0 and serde_json feature are both available. Dependency is correctly specified.

tests/cli_tests/merge.rs (3)

1-4: LGTM!

The module documentation now explains the test scope: validating OrthoConfig layer precedence (defaults, file, env, CLI) and list-value appending behaviour.


18-62: LGTM!

The test comprehensively validates layer precedence and list appending. Each layer's contribution is asserted with clear failure messages. The use of ensure! provides informative diagnostics on failure.


64-111: LGTM!

The integration test properly exercises the full merge pipeline with real config files and environment variables. The EnvLock and EnvVarGuard pattern ensures test isolation. Error propagation via .context() follows the guidelines for clear failure diagnostics.

build.rs (3)

18-19: LGTM!

The cli_l10n module declaration enables build-time access to localization helpers for symbol linking.


26-27: LGTM!

The LocalizedParseFn type alias clearly documents the expected signature for localized CLI parsing. This forces the linker to retain the symbol when the build script is compiled without tests.


74-84: LGTM!

The comment correctly describes the expanded scope (CLI localization, config merge, and host pattern symbols). The const references ensure these symbols remain linked during build script compilation.

src/cli_l10n.rs (5)

1-4: LGTM!

Module documentation clearly explains that this module separates clap localization logic from core CLI definitions.


10-12: LGTM!

The usage_body helper safely strips the "Usage: " prefix with a fallback via unwrap_or.


14-40: LGTM!

The localize_command function correctly applies localization to usage, about, and long_about texts. The fallback chain (existing text → localizer lookup) ensures graceful degradation when translations are missing.


42-64: LGTM!

Using std::mem::take to extract each subcommand avoids unnecessary cloning while enabling mutation. The pattern of building localization keys from subcommand names is clean and extensible.


66-95: LGTM!

The doc comment now explicitly states "When multiple --locale flags are provided, the last one is used." The implementation correctly handles both --locale <value> and --locale=<value> forms, and respects the -- terminator.

src/cli.rs (6)

6-24: LGTM!

The imports are well-organized and bring in the necessary types for OrthoConfig integration, localization, and serde support. The re-export of locale_hint_from_args provides a clean public API surface.


62-70: LGTM!

The error message now correctly uses {trimmed} rather than the original input {s}, ensuring consistency between what is validated and what is reported.


82-154: LGTM!

The Cli struct correctly derives Serialize, Deserialize, and OrthoConfig. The field attributes are well-configured:

  • #[ortho_config(default = ...)] for fields with defaults
  • #[ortho_config(merge_strategy = "append")] for list fields
  • #[serde(skip)] and #[ortho_config(skip_cli)] on command to exclude it from merging

256-275: LGTM!

The helper functions now have documentation as requested in prior reviews:

  • env_provider: describes the prefixed environment provider
  • config_discovery: explains the optional working directory root
  • is_empty_value: clarifies the empty JSON object check

277-306: LGTM!

The cli_overrides_from_matches function correctly filters CLI values to include only those explicitly provided via command line (using ValueSource::CommandLine). This prevents default values from appearing as overrides in the merge pipeline.


229-254: Remove this comment; no duplication exists.

parse_with_localizer_from is only defined in src/cli.rs. It does not exist in src/cli_l10n.rs, which contains only localize_command, locale_hint_from_args, and helper functions.

Likely an incorrect or invalid review comment.


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

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Jan 2, 2026

Reviewer's Guide

Implements OrthoConfig-backed, locale-aware CLI configuration and parsing, wires it through main and runner, adds Fluent-based English/Spanish localisation resources, and extends tests, docs, and build configuration to cover configuration precedence and localised CLI output/errors.

Sequence diagram for OrthoConfig-backed, localised CLI parsing and execution

sequenceDiagram
    actor User
    participant Binary as main_rs
    participant CliMod as cli_rs
    participant CliLoc as cli_localization_rs
    participant Ortho as ortho_config
    participant Runner as runner_mod

    User->>Binary: invoke netsuke [ARGS]
    Binary->>Binary: collect args_os()
    Binary->>CliMod: locale_hint_from_args(args)
    Binary->>Binary: read NETSUKE_LOCALE env
    Binary->>CliLoc: build_localizer(locale)
    CliLoc->>CliLoc: parse_locale / build_en_localizer
    CliLoc-->>Binary: Localizer

    Binary->>CliMod: parse_with_localizer_from(args, Localizer)
    CliMod->>CliMod: localize_command(Cli::command(), Localizer)
    CliMod->>CliMod: try_get_matches_from_mut()
    alt clap parse error
        CliMod->>Ortho: localize_clap_error_with_command(err)
        Ortho-->>CliMod: localized clap::Error
        CliMod-->>Binary: Err(clap::Error)
        Binary->>Binary: is_display_request(err)
        Binary-->>User: print localized help/error
    else parse ok
        CliMod->>CliMod: Cli::from_arg_matches_mut(&mut matches)
        CliMod-->>Binary: (Cli, ArgMatches)
    end

    Binary->>CliMod: merge_with_config(&Cli, &ArgMatches)
    CliMod->>CliMod: MergeComposer::with_capacity(4)
    CliMod->>CliMod: sanitize_value(&Cli::default())
    CliMod->>CliMod: config_discovery(cli.directory)
    CliMod->>Ortho: ConfigDiscovery::compose_layers()
    Ortho-->>CliMod: file_layers
    CliMod->>Ortho: Env::prefixed("NETSUKE_")
    CliMod->>Ortho: Figment::from(env_provider).extract()
    CliMod->>CliMod: cli.extract_user_provided(matches)
    CliMod->>Ortho: LayerComposition::into_merge_result(Cli::merge_from_layers)
    Ortho-->>CliMod: merged Cli
    alt merge error
        CliMod-->>Binary: Err(OrthoError)
        Binary->>Binary: init_tracing(Level::ERROR)
        Binary-->>User: log configuration load failed
    else merge ok
        CliMod-->>Binary: Ok(merged Cli)
    end

    Binary->>Binary: merged_cli.with_default_command()
    Binary->>Binary: init_tracing(max_level)
    Binary->>Runner: run(&merged_cli)
    Runner-->>Binary: Result<()> (build/clean/graph/manifest)
    Binary-->>User: exit code + logs
Loading

Updated class diagram for CLI configuration, commands, and localisation

classDiagram
    class Cli {
        +PathBuf file
        +Option_PathBuf directory
        +Option_usize jobs
        +bool verbose
        +Option_String locale
        +Vec_String fetch_allow_scheme
        +Vec_HostPattern fetch_allow_host
        +Vec_HostPattern fetch_block_host
        +bool fetch_default_deny
        +Option_Commands command
        +default() Cli
    }

    class BuildArgs {
        +Option_PathBuf emit
        +Vec_String targets
    }

    class Commands {
        <<enum>>
        +Build(BuildArgs)
        +Clean
        +Graph
        +Manifest
    }

    class HostPattern {
        -String pattern
        -bool wildcard
        +parse(value: String) Result_HostPattern_HostPatternError
        +matches(input: String) bool
        +from_str(value: String) Result_HostPattern_HostPatternError
    }

    class LayeredLocalizer {
        -Localizer primary
        -Localizer fallback
        +new(primary: Localizer, fallback: Localizer) LayeredLocalizer
        +lookup(id: String, args: LocalizationArgs) Option_String
    }

    class Localizer {
        <<trait>>
        +lookup(id: String, args: LocalizationArgs) Option_String
    }

    class FluentLocalizerBuilder {
        +with_consumer_resources(resources: StringList) FluentLocalizerBuilder
        +disable_defaults() FluentLocalizerBuilder
        +try_build() Result_FluentLocalizer_Error
    }

    class FluentLocalizer {
        +with_en_us_defaults(resources: StringList) Result_FluentLocalizer_Error
        +builder(locale: LanguageIdentifier) FluentLocalizerBuilder
    }

    class NoOpLocalizer {
        +new() NoOpLocalizer
        +lookup(id: String, args: LocalizationArgs) Option_String
    }

    class MergeComposer {
        +with_capacity(size: usize) MergeComposer
        +push_defaults(value: JsonValue)
        +push_layer(value: JsonValue)
        +push_environment(value: JsonValue)
        +push_cli(value: JsonValue)
        +layers() Vec_JsonValue
    }

    class ConfigDiscovery {
        +builder(app: String) ConfigDiscoveryBuilder
        +compose_layers() FileLayers
    }

    class ConfigDiscoveryBuilder {
        +env_var(name: String) ConfigDiscoveryBuilder
        +clear_project_roots() ConfigDiscoveryBuilder
        +add_project_root(dir: PathBuf) ConfigDiscoveryBuilder
        +build() ConfigDiscovery
    }

    class LayerComposition {
        +new(layers: Vec_JsonValue, errors: Vec_OrthoError) LayerComposition
        +into_merge_result(merge_fn: fn) OrthoResult_Cli
    }

    class ArgMatches

    Cli --> Commands : has
    Commands --> BuildArgs : uses
    Cli --> HostPattern : uses

    LayeredLocalizer ..|> Localizer : implements
    FluentLocalizer ..> Localizer : returns
    NoOpLocalizer ..|> Localizer : implements

    ConfigDiscoveryBuilder --> ConfigDiscovery : builds
    ConfigDiscovery --> LayerComposition : produces
    MergeComposer --> LayerComposition : layers

    class CliModuleHelpers {
        +default_manifest_path() PathBuf
        +usage_body(usage: String) String
        +localize_command(command: Command, localizer: Localizer) Command
        +localize_subcommands(command: Command, localizer: Localizer)
        +locale_hint_from_args(args: OsStringList) Option_String
        +parse_with_localizer_from(iter: OsStringList, localizer: Localizer) Result_Cli_ArgMatches
        +merge_with_config(cli: Cli, matches: ArgMatches) OrthoResult_Cli
    }

    CliModuleHelpers --> Cli : constructs
    CliModuleHelpers --> LayeredLocalizer : uses via Localizer
    CliModuleHelpers --> MergeComposer : uses
    CliModuleHelpers --> ConfigDiscovery : uses
    CliModuleHelpers --> ArgMatches : uses
Loading

Flow diagram for configuration precedence and merging in merge_with_config

flowchart TD
    A[Start merge_with_config] --> B[Copy cli.command for later]
    B --> C[Create MergeComposer with_capacity_4]
    C --> D[Sanitize Cli::default and push_defaults]
    D --> E[Build ConfigDiscovery based on cli.directory]
    E --> F[Compose file_layers from ConfigDiscovery]
    F --> G{file_layers.value is empty?}
    G -- Yes --> H[Record required_errors only]
    G -- No --> I[Record all errors; push each file layer]
    H --> J
    I --> J[Prepare Env provider with NETSUKE_ prefix]
    J --> K[Use Figment to extract environment JsonValue]
    K --> L[Push environment layer or record error]
    L --> M[Extract user_provided CLI values from matches]
    M --> N{CLI values empty?}
    N -- No --> O[Push CLI layer into composer]
    N -- Yes --> P[Skip CLI layer]
    O --> Q
    P --> Q[Build LayerComposition from layers and errors]
    Q --> R[Call into_merge_result with Cli::merge_from_layers]
    R --> S{Merge succeeded?}
    S -- No --> T[Return OrthoError from OrthoConfig]
    S -- Yes --> U[Restore original command field on merged Cli]
    U --> V[Return merged Cli]
    T --> W[End]
    V --> W[End]
Loading

File-Level Changes

Change Details Files
Integrate OrthoConfig into the CLI type and add configuration-layer merging utilities.
  • Derive OrthoConfig, Serialize, and Deserialize for Cli and subcommand types and configure the NETSUKE prefix and merge strategies for list and boolean fields.
  • Add locale option parsing and validation, default-manifest helper, and host pattern serde/FromStr support for config-file/env integration.
  • Implement merge_with_config to compose defaults, config files, environment variables, and CLI overrides using OrthoConfig LayerComposition and MergeComposer.
src/cli.rs
src/host_pattern.rs
Introduce localisation plumbing for CLI help and clap errors with English/Spanish Fluent catalogs.
  • Add cli_localization module that builds layered Fluent-based localizers with an English fallback and optional Spanish primary.
  • Localise clap Command usage/about/long_about and subcommand descriptions via Localizer, and add locale_hint_from_args and parse_with_localizer_from helpers.
  • Add Fluent message catalogs for en-US and es-ES covering CLI about/usage/subcommands and clap error messages.
src/cli.rs
src/cli_localization.rs
locales/en-US/messages.ftl
locales/es-ES/messages.ftl
Wire localised, config-backed CLI parsing into main and ensure symbols are linked via build.rs.
  • Update main to collect raw args, infer locale from CLI/env, build a localizer, parse with parse_with_localizer_from, merge configuration layers, and initialise tracing via a helper.
  • Handle configuration merge failures as logged errors with non-zero exit and respect display-only clap errors.
  • Extend build.rs to reference the new CLI helpers so they remain linked in build script builds.
src/main.rs
build.rs
Extend tests and BDD scenarios to cover locale handling, localisation, and configuration precedence.
  • Augment CLI tests with locale cases, error-kind coverage for invalid locale, extraction of user-provided values excluding defaults, and merge-layer precedence/appending behaviour.
  • Add a test to assert Spanish localisation for invalid subcommands via cli_localization and parse_with_localizer_from.
  • Update BDD CLI steps to use localised parsing and add a feature scenario verifying Spanish error text for unknown commands.
tests/cli_tests.rs
tests/bdd/steps/cli.rs
tests/features/cli.feature
Refine documentation and logging messages to describe the new configuration and localisation behaviour and improve clarity.
  • Update netsuke-design and users-guide with OrthoConfig-backed configuration layering semantics, NETSUKE_CONFIG_PATH/NETSUKE_ env handling, and locale selection behaviour.
  • Add an execplan documenting the CLI output/localisation OrthoConfig plan and mark the roadmap CLI output item as done.
  • Tweak runner/process logging messages for Ninja file writing and command execution for clearer wording and examples in docs and logs.
docs/netsuke-design.md
docs/users-guide.md
docs/execplans/cli-output-clarity.md
docs/roadmap.md
src/runner/mod.rs
src/runner/process/file_io.rs
src/cli_policy.rs
Adjust Cargo configuration to include localisation assets and OrthoConfig dependencies.
  • Enable serde_json as a default feature and hook it to ortho_config, add ortho_config as a runtime and build dependency, and add serde/serde_json for build-time tooling.
  • Ensure locales directory is included in the published crate package.
Cargo.toml
Cargo.lock

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

@leynos leynos marked this pull request as ready for review January 2, 2026 03:31
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In the ExecPlan section that specifies adding ortho_config = "0.7.0", consider referencing the existing dependency management conventions (e.g., workspace-wide versions or a tooling file) instead of a hardcoded example version so the document doesn’t drift from the actual Cargo.toml state.
  • Where you describe new Fluent resources (e.g., locales/en-US/messages.ftl), it would help to explicitly tie this to any existing i18n/locale directory layout in the repo or to state that this is a new convention, so future implementers don’t accidentally introduce a parallel structure.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the ExecPlan section that specifies adding `ortho_config = "0.7.0"`, consider referencing the existing dependency management conventions (e.g., workspace-wide versions or a tooling file) instead of a hardcoded example version so the document doesn’t drift from the actual Cargo.toml state.
- Where you describe new Fluent resources (e.g., `locales/en-US/messages.ftl`), it would help to explicitly tie this to any existing i18n/locale directory layout in the repo or to state that this is a new convention, so future implementers don’t accidentally introduce a parallel structure.

## Individual Comments

### Comment 1
<location> `docs/execplans/cli-output-clarity.md:69` </location>
<code_context>
+for CLI behaviour are in `docs/netsuke-design.md` and the roadmap entry in
+`docs/roadmap.md` (Phase 3 → “CLI and Feature Completeness”).
+
+Testing guidance for fixtures, DI, and BDD lives in:
+
+- `docs/rust-testing-with-rstest-fixtures.md`
</code_context>

<issue_to_address>
**suggestion (review_instructions):** DI and BDD are acronyms that are not expanded when first mentioned.

Consider expanding these acronyms on first use, for example: "dependency injection (DI)" and "behaviour-driven development (BDD)", so readers are not expected to infer their meaning from context.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.md`

**Instructions:**
Define uncommon acronyms on first use.

</details>
</issue_to_address>

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

Comment thread docs/execplans/cli-output-clarity.md Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0881164 and 00d6759.

📒 Files selected for processing (1)
  • docs/execplans/cli-output-clarity.md
🧰 Additional context used
📓 Path-based instructions (4)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: When new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve, proactively update the relevant file(s) in the docs/ directory to reflect the latest state.
Documentation must use en-GB-oxendict spelling and grammar ("-ize" / "-yse" / "-our"), with exception for the LICENSE filename.

docs/**/*.md: Use British English (en-GB) spelling with -ize endings (realize, organization), -lyse endings (analyse, paralyse, catalyse), -our endings (colour, behaviour), -re endings (calibre, centre, fibre), double 'l' (cancelled, counsellor), maintained 'e' (likeable, liveable), and -ogue endings (analogue, catalogue)
Use the Oxford comma in documentation: 'ships, planes, and hovercraft'
Treat company names as collective nouns in documentation: 'Concordat Industries are expanding'
Write headings in sentence case in documentation
Use Markdown headings (#, ##, ###) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Provide code blocks and lists using standard Markdown syntax
Always provide a language identifier for fenced code blocks; use plaintext for non-code text
Use - as the first level bullet and renumber lists when items change in documentation
Prefer inline links using [text](url) or angle brackets around the URL in documentation
Ensure blank lines before and after bulleted lists and fenced blocks in documentation
Ensure tables have a delimiter line below the header row in documentation
Expand any uncommon acronym on first use in documentation (e.g., Continuous Integration (CI))
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use GitHub-flavoured numeric footnotes referenced as [^1] in documentation
Number footnotes in order of appearance in the document
Caption every table and every diagram in documentation
Use ![alt text](path/to/image) for embedding figures with brief alt te...

Files:

  • docs/execplans/cli-output-clarity.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown must be wrapped at 120 columns.
Tables and headings in Markdown must not be wrapped.
Use dashes (-) for list bullets in Markdown.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/execplans/cli-output-clarity.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/execplans/cli-output-clarity.md
docs/**/{README,readme,GUIDE,guide,*.md}

📄 CodeRabbit inference engine (docs/adr-001-replace-serde-yml-with-serde-saphyr.md)

Document in Netsuke's README and user guide that the project now supports YAML 1.2 (not YAML 1.1) and that duplicate keys in manifests are no longer permitted

Files:

  • docs/execplans/cli-output-clarity.md
docs/**/!(README).md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

Avoid first and second person personal pronouns outside the README.md file in documentation

Files:

  • docs/execplans/cli-output-clarity.md
🪛 LanguageTool
docs/execplans/cli-output-clarity.md

[style] ~1-~1: Would you like to use the Oxford spelling “Localized”? The spelling ‘Localised’ is also correct.
Context: # Refine CLI Output With OrthoConfig Localised Help This ExecPlan is a living documen...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~14-~14: Would you like to use the Oxford spelling “Localized”? The spelling ‘Localised’ is also correct.
Context: ...les, and CLI flags behave consistently. Localised help strings should be used for CLI usa...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~26-~26: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...rthoConfig-backed CLI configuration and localised help plumbing. - [ ] Refine user-faci...

(OXFORD_SPELLING_Z_NOT_S)


[grammar] ~30-~30: The verb after “to” should be in the base form as part of the to-infinitive. A verb can take many forms, but the base form is always used in the to-infinitive.
Context: ...and test gates; update roadmap entry to done. ## Surprises & Discoveries - Observa...

(TO_NON_BASE)


[style] ~64-~64: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ... which explains configuration layering, localised help via Fluent, and error localisation...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~65-~65: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...g, localised help via Fluent, and error localisation helpers. Design expectations for CLI be...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~94-~94: Possible missing comma found.
Context: ... explicit handling for missing required values and make sure clap defaults do not i...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~98-~98: Would you like to use the Oxford spelling “Localize”? The spelling ‘Localise’ is also correct.
Context: ...i_default_as_absent` where needed). 3. Localise CLI help and clap errors. Create Fluent...

(OXFORD_SPELLING_Z_NOT_S)


[grammar] ~98-~98: The word ‘help’ is a conjunction. In formal texts, use “to”.
Context: ...t` where needed). 3. Localise CLI help and clap errors. Create Fluent resources (f...

(HELP_AND_VB)


[uncategorized] ~100-~100: Do not mix variants of the same word (‘localize’ and ‘localise’) within a single text.
Context: ...FluentLocalizer into CLI parsing. Use command().localize(&localizer) before parsing and `loc...

(EN_WORD_COHERENCY)


[uncategorized] ~101-~101: Do not mix variants of the same word (‘localize’ and ‘localise’) within a single text.
Context: ...lize(&localizer) before parsing andlocalize_clap_error_with_command` on errors. Ens...

(EN_WORD_COHERENCY)


[style] ~102-~102: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...k path preserves stock clap output when localisation fails. 4. Refine CLI output messages. ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~109-~109: Would you like to use the Oxford spelling “centralize”? The spelling ‘centralise’ is also correct.
Context: ...troduce a small output helper module to centralise user message formatting. 5. Add tes...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~117-~117: Would you like to use the Oxford spelling “Localized”? The spelling ‘Localised’ is also correct.
Context: ...` to avoid touching process state. - Localised help contains expected copy, and clap e...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~117-~117: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...ains expected copy, and clap errors are localised when possible. - Unhappy paths ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~129-~129: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...lain the new configuration layering, localised help, and any changes to CLI output. ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~147-~147: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: .... Implement OrthoConfig integration and localisation. Update or add the relevant files an...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~168-~168: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...elp(viacargo run -- --help`) prints localised, plain-language descriptions for ever...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~171-~171: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ... Error output for invalid CLI inputs is localised when a translation exists. - Configur...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~177-~177: Loose punctuation mark.
Context: ... and config layering. - make check-fmt, make lint, and make test pass. - `d...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~183-~183: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...potence and Recovery - OrthoConfig and localisation changes are safe to re-run; regenerate ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~185-~185: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...nd help output as often as needed. - If localisation setup fails, fall back to default clap ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~187-~187: Consider using a different verb for a more formal wording.
Context: ... error output. - If tests fail mid-run, fix the underlying issue and re-run the sam...

(FIX_RESOLVE)


[style] ~194-~194: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...idence: - netsuke --help output with localised strings (from /tmp/netsuke-help.log...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~196-~196: Possible missing comma found.
Context: ...tmp/netsuke-help.log`). - A failing CLI invocation showing localised error output (record ...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~196-~196: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...g`). - A failing CLI invocation showing localised error output (record the command and ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~214-~214: Would you like to use the Oxford spelling “localizer”? The spelling ‘localiser’ is also correct.
Context: ...e CLI parsing in src/main.rs uses the localiser and merges config layers before calli...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~222-~222: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...ted to cover OrthoConfig integration, localised help, CLI output clarity, and test/docu...

(OXFORD_SPELLING_Z_NOT_S)

🔍 Remote MCP

Summary of Findings

Based on comprehensive exploration of the Netsuke repository through its documentation and codebase, here are the key findings relevant for reviewing PR #254:

What This PR Adds

The PR introduces a new ExecPlan document at docs/execplans/cli-output-clarity.md - a "living blueprint" for refining CLI output with OrthoConfig-backed localization. This is a documentation-only PR with no functional code changes.

Important Context About the Repository

  1. Project Structure: Netsuke is a build system compiler (not executor) that transforms YAML manifests with Jinja2 templating into Ninja build files. It implements a six-stage processing pipeline from manifest loading through Ninja code generation.

  2. ExecPlan Concept: While ExecPlans aren't currently documented in the codebase, they appear to be planning documents for major initiatives. The new cli-output-clarity.md file follows the pattern of outlining purpose, progress, decisions, validation criteria, and dependencies.

  3. CLI Architecture (source: deepwiki):

    • Built with clap derive API
    • Currently supports three commands: build (default), clean, and graph
    • Provides options for --file, --directory (-C), --jobs (-j), and --verbose (-v)
    • CLI is defined in src/cli.rs and entry point in src/main.rs
  4. OrthoConfig and Localization: While the PR mentions "OrthoConfig-backed configuration" and localization, these components don't exist yet in the codebase. This confirms the ExecPlan is a forward-looking design document for future implementation.

  5. Repository Quality Standards (source: deepwiki):

    • Strict code quality through clippy with denial of unsafe patterns
    • Comprehensive multi-layer testing (unit, BDD, snapshot, integration)
    • Strong emphasis on security (shell escaping via shell-quote, capability-based I/O via cap-std)
    • Clear error handling strategy using thiserror/anyhow
    • File system operations use UTF-8 paths (camino) and sandboxed access (cap-std)

Verification Steps for Review

As mentioned in the PR, reviewers should:

  1. ✅ Verify the ExecPlan aligns with repository goals and design patterns (evidenced by the comprehensive design documentation available)
  2. ✅ Ensure the CLI output clarity initiative fits with current architecture (CLI is a clear, bounded subsystem in src/cli.rs)
  3. ✅ Validate that proposed scope doesn't conflict with existing functionality (clean/graph commands are currently stubs awaiting implementation)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: Sourcery review
🔇 Additional comments (1)
docs/execplans/cli-output-clarity.md (1)

1-222: Document structure, content, and alignment with ExecPlan purpose are sound.

The ExecPlan file provides clear purpose, context, concrete steps, validation criteria, and dependencies. Heading hierarchy, code formatting, checklist syntax, and reference documentation links are all correctly structured. Once the three preceding issues (line wrapping, grammar, spelling) are resolved, this document is ready for integration.

Comment thread docs/execplans/cli-output-clarity.md
Comment thread docs/execplans/cli-output-clarity.md Outdated
Comment thread docs/execplans/cli-output-clarity.md
Comment thread docs/execplans/cli-output-clarity.md Outdated
- Introduce OrthoConfig-backed layering for CLI configuration with priorities: defaults, config files, env vars, CLI flags
- Make CLI defaults absent so they do not mask config file or environment values
- Support configuration discovery honoring NETSUKE_CONFIG_PATH and standard OS config locations
- Add Fluent-based localisation of CLI help and error messages with English and Spanish support
- Parse and apply --locale and NETSUKE_LOCALE environment variable for localisation
- Enhance CLI parsing to produce localized error messages
- Update CLI documentation and user guide with localisation and config layering details
- Add unit tests and behavioural tests for configuration merging and localisation
- Modify main executable to perform config merging and setup localized CLI parsing

This improves user experience by supporting layered, overrideable configurations
and localized CLI output, improving clarity and internationalisation.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Refine CLI output clarity with OrthoConfig localisation (docs) OrthoConfig-backed CLI config, localisation, and tests Jan 2, 2026
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 2, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

src/host_pattern.rs

Comment on file

//! The module centralises normalisation and matching logic so CLI parsing and
//! runtime policy evaluation agree on allowable host syntax.

use serde::{Deserialize, Serialize};

❌ New issue: String Heavy Function Arguments
In this module, 58.3% of all arguments to its 9 functions are strings. The threshold for string arguments is 39.0%

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 2, 2026

@sourcery-ai review

@coderabbitai

This comment was marked as resolved.

Changed test assertion to use `merged.file.as_path() == Path::new("Configfile")` instead of `PathBuf::from("Configfile")` for more idiomatic path comparison in tests.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title OrthoConfig-backed CLI config, localisation, and tests Refine CLI output clarity with tests Jan 2, 2026
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 9 issues, and left some high level feedback:

  • In main.rs, the is_display_request(&err) branch currently calls err.exit() in both cases, making the if condition redundant; consider either simplifying to a single err.exit() or using the predicate to differentiate behavior (e.g., exit code or logging) for display vs error requests.
  • There are two parse_locale helpers (cli::parse_locale and cli_localization::parse_locale) with overlapping concerns but different return types; consider consolidating or renaming them to make the separation of responsibilities clearer and avoid future confusion.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `main.rs`, the `is_display_request(&err)` branch currently calls `err.exit()` in both cases, making the `if` condition redundant; consider either simplifying to a single `err.exit()` or using the predicate to differentiate behavior (e.g., exit code or logging) for display vs error requests.
- There are two `parse_locale` helpers (`cli::parse_locale` and `cli_localization::parse_locale`) with overlapping concerns but different return types; consider consolidating or renaming them to make the separation of responsibilities clearer and avoid future confusion.

## Individual Comments

### Comment 1
<location> `src/main.rs:20-22` </location>
<code_context>
+    let locale = locale_hint.as_deref().or(env_locale.as_deref());
+    let localizer = cli_localization::build_localizer(locale);
+
+    let (parsed_cli, matches) = match cli::parse_with_localizer_from(args, localizer.as_ref()) {
+        Ok(parsed) => parsed,
+        Err(err) => {
+            if is_display_request(&err) {
+                err.exit();
</code_context>

<issue_to_address>
**issue:** The `is_display_request` branch is redundant because `err.exit()` is unconditionally called.

Because `err.exit()` terminates the process, the second call after the `if is_display_request(&err)` block is unreachable. Consider removing the `if is_display_request` branch (keeping a single `err.exit()`) or changing it to perform some different behavior (e.g., a different exit code) if that was intended.
</issue_to_address>

### Comment 2
<location> `src/cli.rs:253-262` </location>
<code_context>
+fn localize_subcommands(command: &mut clap::Command, localizer: &dyn Localizer) {
</code_context>

<issue_to_address>
**suggestion (performance):** Subcommands are cloned unnecessarily when applying localized `about`/`long_about` text.

Inside `localize_subcommands`, you can drop the `subcommand.clone()` and reassignment. Since Clap’s `about`/`long_about` return `&mut Command`, call them directly on `subcommand` to avoid extra allocations and simplify the code.
</issue_to_address>

### Comment 3
<location> `src/cli.rs:339-348` </location>
<code_context>
+pub fn merge_with_config(cli: &Cli, matches: &ArgMatches) -> OrthoResult<Cli> {
</code_context>

<issue_to_address>
**question:** Preserving `cli.command` after merging layers prevents configuration from influencing the default subcommand.

Currently `merge_with_config` clones `cli.command` at the start and restores it after merging, so any `command` value from config is discarded. If config should be able to set a default subcommand (overridden by explicit CLI args), this logic prevents it. If instead config-driven subcommands are disallowed, consider excluding `command` from the merge entirely (e.g., `#[ortho_config(skip)]`) so that intent is enforced and self-documenting.
</issue_to_address>

### Comment 4
<location> `Cargo.toml:18-20` </location>
<code_context>

 [features]
-default = []
+default = ["serde_json"]
 legacy-digests = ["sha1", "md5"]
+serde_json = ["ortho_config/serde_json"]

 [dependencies]
</code_context>

<issue_to_address>
**question (bug_risk):** Using `serde_json` in the public API without gating the code may break `default-features = false` consumers.

Because `serde_json` is now a default feature but `serde_json::Value` is used directly in `cli::merge_with_config` without `cfg` gating, `netsuke` still requires `serde_json` even when built with `default-features = false`. To keep `serde_json` truly optional, gate the relevant code with `#[cfg(feature = "serde_json")]` (and provide an alternative or stub when disabled), or drop the separate feature if it isn’t meant to be optional.
</issue_to_address>

### Comment 5
<location> `tests/cli_tests.rs:315-284` </location>
<code_context>
+fn cli_merge_layers_respects_precedence_and_appends_lists() -> Result<()> {
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test that exercises `merge_with_config` end-to-end instead of only `merge_from_layers`

This test covers precedence and list semantics at the `Cli::merge_from_layers` level, but `merge_with_config` also wires in `ConfigDiscovery`, env vars, and `extract_user_provided` (including the `is_empty_value` short-circuit). Please add an integration-style unit test that exercises `merge_with_config` end-to-end (config discovery from a temp dir, `NETSUKE_` env vars, CLI args via `ArgMatches`) and asserts the final `Cli` reflects the correct precedence and ignores empty CLI overrides.

Suggested implementation:

```rust
#[rstest]
fn cli_merge_with_config_respects_precedence_and_ignores_empty_cli_values() -> Result<()> {
    use std::fs;
    use std::path::PathBuf;

    // Arrange: create a temporary config root with a config file
    let tmp_dir = tempfile::tempdir().context("failed to create temp dir for config discovery")?;
    let config_root: PathBuf = tmp_dir.path().to_path_buf();

    // Config file sets a few values that will be overridden by env and CLI
    // - jobs: 2 (to be overridden)
    // - fetch_allow_scheme: ["https"] (to be appended to / overridden)
    // - some other option to ensure config is picked up at all
    let config_toml = r#"
        jobs = 2
        fetch_allow_scheme = ["https"]
    "#;
    fs::write(config_root.join("netsuke.toml"), config_toml)
        .context("failed to write netsuke.toml")?;

    // Arrange: set NETSUKE_ env vars that override config
    // - NETSUKE_JOBS should win over config value, unless overridden by non-empty CLI
    // - NETSUKE_FETCH_ALLOW_SCHEME should be merged/overridden according to semantics
    std::env::set_var("NETSUKE_JOBS", "4");
    std::env::set_var("NETSUKE_FETCH_ALLOW_SCHEME", "http");

    // Arrange: build CLI ArgMatches simulating real invocation
    // We pass:
    // - --jobs with an *empty* string, which should be treated as "no user override"
    //   and therefore ignored by `extract_user_provided` / `is_empty_value`.
    // - --fetch-allow-scheme multiple times to exercise list semantics (append/override).
    //
    // The expectations are:
    // - `jobs` should *not* be overridden by the empty CLI value, so it should resolve
    //   to the env var value (4), not the config value (2) and not default.
    // - `fetch_allow_scheme` should reflect the precedence rules including
    //   merging/appending from config/env/CLI (final assertion below tailored to actual semantics).
    //
    // NOTE: if `Cli::command()` is not available, adjust this to however ArgMatches
    // are constructed in the main binary.
    let matches = Cli::command().get_matches_from([
        "netsuke",
        "--jobs",
        "", // empty value: should be ignored as a user override
        "--fetch-allow-scheme",
        "ssh",
        "--fetch-allow-scheme",
        "git",
    ]);

    // Arrange: wire ConfigDiscovery using the temp config root
    // Adjust constructor if your real type differs.
    let discovery = ConfigDiscovery::from_root(config_root);

    // Act: perform full merge, including:
    // - config discovery (using ConfigDiscovery)
    // - env vars (NETSUKE_)
    // - CLI args (ArgMatches)
    // - extraction of user-provided values and empty-value short-circuit
    let mut cli = Cli::default();
    cli.merge_with_config(&matches, &discovery)
        .context("merge_with_config failed")?;

    // Assert: precedence and empty-override semantics

    // `jobs`:
    // - default: Cli::default().jobs
    // - config: 2
    // - env: NETSUKE_JOBS=4
    // - CLI: "--jobs ''" (empty, should be ignored)
    //
    // So the final value should come from env, not config and not be overridden by
    // the empty CLI value.
    assert_eq!(
        cli.jobs, 4,
        "empty CLI override for jobs should be ignored; env var should win over config"
    );

    // `fetch_allow_scheme`:
    // Base config: ["https"] from netsuke.toml
    // Env: "http" from NETSUKE_FETCH_ALLOW_SCHEME
    // CLI: ["ssh", "git"] via multiple --fetch-allow-scheme flags
    //
    // The exact expected list depends on semantics of `merge_from_layers` for lists:
    // - If it *appends* layers, then lower-precedence values appear first.
    // - If it *overrides* with the highest precedence, only the CLI list appears.
    //
    // Here we assert the "append with increasing precedence" behavior:
    //   config ("https") + env ("http") + CLI ("ssh", "git")
    // Adjust this expectation if your merging semantics differ.
    assert_eq!(
        cli.fetch_allow_scheme,
        vec![
            "https".to_string(),
            "http".to_string(),
            "ssh".to_string(),
            "git".to_string()
        ],
        "merge_with_config should merge list fields respecting precedence across \
         config file, NETSUKE_ env vars, and CLI args"
    );

    Ok(())
}

#[rstest]

```

This new test assumes some APIs and types that may need to be adjusted to match your actual code:

1. **ConfigDiscovery construction**
   - The test uses `ConfigDiscovery::from_root(config_root)`. If the real API is different (e.g. `ConfigDiscovery::new(Some(config_root))` or a builder pattern), update the construction accordingly, while still pointing it at `config_root` so that `netsuke.toml` is discovered.

2. **CLI ArgMatches construction**
   - The test uses `Cli::command().get_matches_from(...)`. If your `Cli` type uses a different method (e.g. `Cli::command_from_clap()` or a global `command()` function), replace this line with however you normally obtain `ArgMatches` for `Cli`.

3. **Field names and types**
   - The assertions reference `cli.jobs` (integer) and `cli.fetch_allow_scheme` (`Vec<String>`). If your `Cli` struct uses different field names or types, update the assertions and the TOML/env/CLI inputs to match.
   - Ensure that `Cli::default()` and `Cli::merge_with_config(&matches, &discovery)` exist and are in scope in `tests/cli_tests.rs`.

4. **Crate imports**
   - The test uses:
     - `tempfile::tempdir`
     - `anyhow::Context` (via `.context(...)`)
     - `serde_json::json` / the `Result` alias already used elsewhere in the file.
   - If these imports are not yet present at the top of `tests/cli_tests.rs`, add:
     - `use tempfile;`
     - `use anyhow::Context;`
     - Any others needed to compile.

5. **List merge semantics**
   - The expected `fetch_allow_scheme` value assumes the lists from config, env, and CLI are **appended in precedence order**: config < env < CLI.
   - If your actual `merge_from_layers` implementation uses a different strategy (e.g. "highest precedence overwrites entire list"), adjust the expected vector in the assertion to match those semantics while still verifying that `merge_with_config` correctly wires config discovery, env vars, CLI args, and empty CLI values.
</issue_to_address>

### Comment 6
<location> `tests/cli_tests.rs:361-284` </location>
<code_context>
+}
+
+#[rstest]
+fn cli_localises_invalid_subcommand_in_spanish() -> Result<()> {
+    let localizer = cli_localization::build_localizer(Some("es-ES"));
+    let err = netsuke::cli::parse_with_localizer_from(
+        ["netsuke", "--locale", "es-ES", "unknown"],
+        localizer.as_ref(),
+    )
+    .err()
+    .context("parser should reject invalid subcommand")?;
+    ensure!(
+        err.to_string().contains("Subcomando desconocido"),
+        "expected Spanish localisation, got: {err}",
+    );
+    Ok(())
+}
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for `locale_hint_from_args` to cover argument parsing edge cases

`locale_hint_from_args` is only covered indirectly via `main`/BDD, so its behavior isn’t locked down. Please add focused unit tests, e.g.:
- `--locale es-ES` and `--locale=en-US` forms
- `--locale` as the last arg (no value) returning `None` without panicking
- Arguments containing `--` so locale parsing ignores positional args after end-of-options (if required)
- Multiple `--locale` flags to document which one takes precedence

This will clarify and stabilize the locale selection contract for future refactors.

Suggested implementation:

```rust
#[rstest]
fn locale_hint_from_args_accepts_space_form() -> Result<()> {
    let args = ["netsuke", "--locale", "es-ES"];
    let hint = netsuke::cli::locale_hint_from_args(&args);
    ensure!(
        hint.as_deref() == Some("es-ES"),
        "expected Some(\"es-ES\"), got: {hint:?}"
    );
    Ok(())
}

#[rstest]
fn locale_hint_from_args_accepts_equals_form() -> Result<()> {
    let args = ["netsuke", "--locale=es-ES"];
    let hint = netsuke::cli::locale_hint_from_args(&args);
    ensure!(
        hint.as_deref() == Some("es-ES"),
        "expected Some(\"es-ES\"), got: {hint:?}"
    );
    Ok(())
}

#[rstest]
fn locale_hint_from_args_trailing_locale_flag_yields_none() -> Result<()> {
    let args = ["netsuke", "--locale"];
    let hint = netsuke::cli::locale_hint_from_args(&args);
    ensure!(
        hint.is_none(),
        "expected None for trailing --locale without value, got: {hint:?}"
    );
    Ok(())
}

#[rstest]
fn locale_hint_from_args_ignores_args_after_double_dash() -> Result<()> {
    let args = ["netsuke", "--verbose", "--", "--locale", "es-ES"];
    let hint = netsuke::cli::locale_hint_from_args(&args);
    ensure!(
        hint.is_none(),
        "expected None when --locale appears after end-of-options \"--\", got: {hint:?}"
    );
    Ok(())
}

#[rstest]
fn locale_hint_from_args_uses_last_locale_flag() -> Result<()> {
    let args = ["netsuke", "--locale", "es-ES", "--locale", "en-US"];
    let hint = netsuke::cli::locale_hint_from_args(&args);
    ensure!(
        hint.as_deref() == Some("en-US"),
        "expected last --locale to win (\"en-US\"), got: {hint:?}"
    );
    Ok(())
}

#[rstest]
fn cli_extract_user_provided_omits_defaults() -> Result<()> {

```

- If `locale_hint_from_args` is not exposed as `netsuke::cli::locale_hint_from_args`, adjust the path or add a `use` at the top of `tests/cli_tests.rs`, e.g.:
  `use crate::cli::locale_hint_from_args;` and call it as `locale_hint_from_args(&args)`.
- If the current implementation prefers the *first* `--locale` instead of the last, update the expectation in `locale_hint_from_args_uses_last_locale_flag` accordingly (and rename the test to reflect the actual contract).
- If your implementation currently *does* consider `--locale` after `--`, either change the implementation to match the test (ignoring post-`--` options) or update the test to assert the current behaviour you intend to keep.
</issue_to_address>

### Comment 7
<location> `docs/users-guide.md:543` </location>
<code_context>
+`$HOME/.netsuke.toml`, and finally the project root.
+
+Environment variables use the `NETSUKE_` prefix (for example,
+`NETSUKE_JOBS=8`). Use `__` to separate nested keys if you need to match
+structured configuration.
+
</code_context>

<issue_to_address>
**suggestion (review_instructions):** The sentence "if you need to match" uses the 2nd person pronoun "you", which the style guide forbids.

Consider rephrasing to avoid the explicit 2nd person, for example: "Use `__` to separate nested keys when matching structured configuration."

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.md`

**Instructions:**
Avoid 2nd person or 1st person pronouns ("I", "you", "we").

</details>
</issue_to_address>

### Comment 8
<location> `docs/execplans/cli-output-clarity.md:78` </location>
<code_context>
+for CLI behaviour are in `docs/netsuke-design.md` and the roadmap entry in
+`docs/roadmap.md` (Phase 3 → “CLI and Feature Completeness”).
+
+Testing guidance for fixtures, DI, and BDD lives in:
+
+- `docs/rust-testing-with-rstest-fixtures.md`
</code_context>

<issue_to_address>
**suggestion (review_instructions):** The acronyms "DI" and "BDD" are introduced without expansion, which conflicts with the requirement to define uncommon acronyms on first use.

Consider expanding both acronyms on first mention, for example: "fixtures, dependency injection (DI), and behaviour-driven development (BDD)".

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.md`

**Instructions:**
Define uncommon acronyms on first use.

</details>
</issue_to_address>

### Comment 9
<location> `docs/execplans/cli-output-clarity.md:82` </location>
<code_context>
+
+- `docs/rust-testing-with-rstest-fixtures.md`
+- `docs/reliable-testing-in-rust-via-dependency-injection.md`
+- `docs/behavioural-testing-in-rust-with-cucumber.md` (applies to Gherkin
+  structure, even though we use `rstest-bdd`)
+- `docs/rust-doctest-dry-guide.md` (for any new public API docs)
</code_context>

<issue_to_address>
**suggestion (review_instructions):** The parenthetical "even though we use `rstest-bdd`" uses the 1st person plural pronoun "we", which is disallowed by the style guide.

Rephrase the parenthetical to avoid 1st person, for example: "(applies to Gherkin structure, even though `rstest-bdd` is used instead)".

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.md`

**Instructions:**
Avoid 2nd person or 1st person pronouns ("I", "you", "we").

</details>
</issue_to_address>

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

Comment thread src/main.rs Outdated
Comment thread src/cli.rs Outdated
Comment thread src/cli.rs
Comment thread Cargo.toml Outdated
Comment thread tests/cli_tests.rs Outdated
Comment thread tests/cli_tests.rs Outdated
Comment thread docs/users-guide.md Outdated
Comment thread docs/execplans/cli-output-clarity.md Outdated
Comment thread docs/execplans/cli-output-clarity.md
- Added tests for locale_hint_from_args covering various argument forms and conditions.
- Added tests for cli_merge_with_config to verify precedence and skipping empty CLI layers.
- Introduced EnvGuard for managing environment variables in tests safely.
- Improved testing coverage and robustness for CLI parsing and merging behavior.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Refine CLI output clarity with tests Refine CLI output localisation with OrthoConfig and tests Jan 2, 2026
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/cli_tests.rs (1)

1-502: File exceeds 400-line limit.

At 502 lines, this file exceeds the 400-line maximum specified in the coding guidelines. Split locale-related tests, merge-related tests, and network policy tests into separate test modules.

♻️ Duplicate comments (1)
Cargo.toml (1)

17-20: The cfg-gating concern was raised previously.

The past review flagged that serde_json::Value usage in cli::merge_with_config lacks #[cfg(feature = "serde_json")] guards, which breaks default-features = false consumers.

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00d6759 and 187011a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • Cargo.toml
  • build.rs
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md
  • docs/roadmap.md
  • docs/users-guide.md
  • locales/en-US/messages.ftl
  • locales/es-ES/messages.ftl
  • src/cli.rs
  • src/cli_localization.rs
  • src/cli_policy.rs
  • src/host_pattern.rs
  • src/lib.rs
  • src/main.rs
  • src/runner/mod.rs
  • src/runner/process/file_io.rs
  • src/runner/process/mod.rs
  • tests/bdd/steps/cli.rs
  • tests/cli_tests.rs
  • tests/features/cli.feature
🧰 Additional context used
📓 Path-based instructions (6)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • src/cli_policy.rs
  • src/cli_localization.rs
  • src/runner/mod.rs
  • build.rs
  • src/main.rs
  • tests/bdd/steps/cli.rs
  • src/lib.rs
  • tests/cli_tests.rs
  • src/runner/process/mod.rs
  • src/runner/process/file_io.rs
  • src/cli.rs
  • src/host_pattern.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • src/cli_policy.rs
  • src/cli_localization.rs
  • src/runner/mod.rs
  • build.rs
  • src/main.rs
  • tests/bdd/steps/cli.rs
  • src/lib.rs
  • tests/cli_tests.rs
  • src/runner/process/mod.rs
  • src/runner/process/file_io.rs
  • src/cli.rs
  • src/host_pattern.rs
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: When new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve, proactively update the relevant file(s) in the docs/ directory to reflect the latest state.
Documentation must use en-GB-oxendict spelling and grammar ("-ize" / "-yse" / "-our"), with exception for the LICENSE filename.

docs/**/*.md: Use British English (en-GB) spelling with -ize endings (realize, organization), -lyse endings (analyse, paralyse, catalyse), -our endings (colour, behaviour), -re endings (calibre, centre, fibre), double 'l' (cancelled, counsellor), maintained 'e' (likeable, liveable), and -ogue endings (analogue, catalogue)
Use the Oxford comma in documentation: 'ships, planes, and hovercraft'
Treat company names as collective nouns in documentation: 'Concordat Industries are expanding'
Write headings in sentence case in documentation
Use Markdown headings (#, ##, ###) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Provide code blocks and lists using standard Markdown syntax
Always provide a language identifier for fenced code blocks; use plaintext for non-code text
Use - as the first level bullet and renumber lists when items change in documentation
Prefer inline links using [text](url) or angle brackets around the URL in documentation
Ensure blank lines before and after bulleted lists and fenced blocks in documentation
Ensure tables have a delimiter line below the header row in documentation
Expand any uncommon acronym on first use in documentation (e.g., Continuous Integration (CI))
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use GitHub-flavoured numeric footnotes referenced as [^1] in documentation
Number footnotes in order of appearance in the document
Caption every table and every diagram in documentation
Use ![alt text](path/to/image) for embedding figures with brief alt te...

Files:

  • docs/users-guide.md
  • docs/roadmap.md
  • docs/netsuke-design.md
  • docs/execplans/cli-output-clarity.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown must be wrapped at 120 columns.
Tables and headings in Markdown must not be wrapped.
Use dashes (-) for list bullets in Markdown.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/users-guide.md
  • docs/roadmap.md
  • docs/netsuke-design.md
  • docs/execplans/cli-output-clarity.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/users-guide.md
  • docs/roadmap.md
  • docs/netsuke-design.md
  • docs/execplans/cli-output-clarity.md
docs/**/{README,readme,GUIDE,guide,*.md}

📄 CodeRabbit inference engine (docs/adr-001-replace-serde-yml-with-serde-saphyr.md)

Document in Netsuke's README and user guide that the project now supports YAML 1.2 (not YAML 1.1) and that duplicate keys in manifests are no longer permitted

Files:

  • docs/users-guide.md
  • docs/roadmap.md
  • docs/netsuke-design.md
  • docs/execplans/cli-output-clarity.md
docs/**/!(README).md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

Avoid first and second person personal pronouns outside the README.md file in documentation

Files:

  • docs/users-guide.md
  • docs/roadmap.md
  • docs/netsuke-design.md
  • docs/execplans/cli-output-clarity.md
Cargo.toml

📄 CodeRabbit inference engine (AGENTS.md)

Cargo.toml: In Rust Cargo.toml, use explicit version ranges and keep dependencies up-to-date.
All crate versions specified in Cargo.toml must use SemVer-compatible caret requirements (e.g., some-crate = "1.2.3") to allow safe non-breaking updates.
The use of wildcard (*) or open-ended inequality (>=) version requirements in Cargo.toml is strictly forbidden.
Tilde requirements (~) in Cargo.toml should only be used where a dependency must be locked to patch-level updates for a specific, documented reason.

Files:

  • Cargo.toml
🧠 Learnings (1)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • src/cli_policy.rs
  • src/cli_localization.rs
  • src/runner/mod.rs
  • build.rs
  • src/main.rs
  • tests/bdd/steps/cli.rs
  • src/lib.rs
  • tests/cli_tests.rs
  • src/runner/process/mod.rs
  • src/runner/process/file_io.rs
  • src/cli.rs
  • src/host_pattern.rs
🧬 Code graph analysis (4)
build.rs (1)
src/cli.rs (3)
  • locale_hint_from_args (280-305)
  • merge_with_config (356-397)
  • parse_with_localizer_from (315-332)
src/main.rs (2)
src/cli.rs (3)
  • locale_hint_from_args (280-305)
  • parse_with_localizer_from (315-332)
  • merge_with_config (356-397)
src/cli_localization.rs (1)
  • build_localizer (65-82)
tests/bdd/steps/cli.rs (2)
src/cli.rs (2)
  • locale_hint_from_args (280-305)
  • parse_with_localizer_from (315-332)
src/cli_localization.rs (1)
  • build_localizer (65-82)
src/cli.rs (1)
src/host_pattern.rs (1)
  • matches (165-177)
🪛 LanguageTool
docs/users-guide.md

[uncategorized] ~488-~488: Loose punctuation mark.
Context: ...e logging output. - --locale <LOCALE>: Localise CLI help and error messages (f...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~488-~488: Would you like to use the Oxford spelling “Localize”? The spelling ‘Localise’ is also correct.
Context: ...logging output. - --locale <LOCALE>: Localise CLI help and error messages (for exampl...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~496-~496: Loose punctuation mark.
Context: ...ions: - --fetch-allow-scheme <SCHEME>: Allow additional URL schemes beyond the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~499-~499: Loose punctuation mark.
Context: ...defaults. - --fetch-allow-host <HOST>: Allow the provided hostnames when defau...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~502-~502: Loose punctuation mark.
Context: ...pported). - --fetch-block-host <HOST>: Always block the provided hostnames (wi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~505-~505: Loose punctuation mark.
Context: ...e allowlisted. - --fetch-default-deny: Deny all hosts by default and only perm...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~530-~530: Would you like to use the Oxford spelling “Localization”? The spelling ‘Localisation’ is also correct.
Context: ...s like --html. ### Configuration and Localisation Netsuke layers configuration in this o...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~546-~546: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...orNETSUKE_LOCALE to select localised CLI copy and error messages. Spanish (...

(OXFORD_SPELLING_Z_NOT_S)

docs/execplans/cli-output-clarity.md

[style] ~1-~1: Would you like to use the Oxford spelling “Localized”? The spelling ‘Localised’ is also correct.
Context: # Refine CLI Output With OrthoConfig Localised Help This ExecPlan is a living documen...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~14-~14: Would you like to use the Oxford spelling “Localized”? The spelling ‘Localised’ is also correct.
Context: ...les, and CLI flags behave consistently. Localised help strings should be used for CLI usa...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~26-~26: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...rthoConfig-backed CLI configuration and localised help plumbing. - [x] Refine user-faci...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~45-~45: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...dex) - Decision: Provide Fluent-backed localisation with English defaults and a Spanish c...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~47-~47: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...nsumer resource. Rationale: Validates localised help/error support while keeping fallba...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~53-~53: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...es: OrthoConfig configuration layering, localisation resources (including Spanish), update...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~73-~73: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ... which explains configuration layering, localised help via Fluent, and error localisation...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~74-~74: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...g, localised help via Fluent, and error localisation helpers. Design expectations for CLI be...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~105-~105: Possible missing comma found.
Context: ... explicit handling for missing required values and make sure clap defaults do not i...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~109-~109: Would you like to use the Oxford spelling “Localize”? The spelling ‘Localise’ is also correct.
Context: ...efault_as_absent` where needed). 3. Localise CLI help and clap errors. Create Fluent...

(OXFORD_SPELLING_Z_NOT_S)


[grammar] ~109-~109: The word ‘help’ is a conjunction. In formal texts, use “to”.
Context: ...where needed). 3. Localise CLI help and clap errors. Create Fluent resources (f...

(HELP_AND_VB)


[uncategorized] ~111-~111: Do not mix variants of the same word (‘localize’ and ‘localise’) within a single text.
Context: ...FluentLocalizer into CLI parsing. Use command().localize(&localizer) before parsing and `loc...

(EN_WORD_COHERENCY)


[uncategorized] ~112-~112: Do not mix variants of the same word (‘localize’ and ‘localise’) within a single text.
Context: ...lize(&localizer) before parsing andlocalize_clap_error_with_command` on errors. Ens...

(EN_WORD_COHERENCY)


[style] ~113-~113: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...k path preserves stock clap output when localisation fails. 4. Refine CLI output messages. ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~128-~128: Would you like to use the Oxford spelling “Localized”? The spelling ‘Localised’ is also correct.
Context: ...` to avoid touching process state. - Localised help contains expected copy, and clap e...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~128-~128: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...ains expected copy, and clap errors are localised when possible. - Unhappy paths ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~140-~140: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...lain the new configuration layering, localised help, and any changes to CLI output. ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~158-~158: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: .... Implement OrthoConfig integration and localisation. Update or add the relevant files an...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~179-~179: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...elp(viacargo run -- --help`) prints localised, plain-language descriptions for ever...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~182-~182: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ... Error output for invalid CLI inputs is localised when a translation exists. - Configur...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~188-~188: Loose punctuation mark.
Context: ... and config layering. - make check-fmt, make lint, and make test pass. - `d...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~194-~194: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...potence and Recovery - OrthoConfig and localisation changes are safe to re-run; regenerate ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~196-~196: Would you like to use the Oxford spelling “localization”? The spelling ‘localisation’ is also correct.
Context: ...nd help output as often as needed. - If localisation setup fails, fall back to default clap ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~198-~198: Consider using a different verb for a more formal wording.
Context: ... error output. - If tests fail mid-run, fix the underlying issue and re-run the sam...

(FIX_RESOLVE)


[style] ~205-~205: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...idence: - netsuke --help output with localised strings (from /tmp/netsuke-help.log...

(OXFORD_SPELLING_Z_NOT_S)


[uncategorized] ~207-~207: Possible missing comma found.
Context: ...tmp/netsuke-help.log`). - A failing CLI invocation showing localised error output (record ...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~207-~207: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...g`). - A failing CLI invocation showing localised error output (record the command and ...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~225-~225: Would you like to use the Oxford spelling “localizer”? The spelling ‘localiser’ is also correct.
Context: ...e CLI parsing in src/main.rs uses the localiser and merges config layers before calli...

(OXFORD_SPELLING_Z_NOT_S)


[style] ~233-~233: Would you like to use the Oxford spelling “localized”? The spelling ‘localised’ is also correct.
Context: ...ted to cover OrthoConfig integration, localised help, CLI output clarity, and test/docu...

(OXFORD_SPELLING_Z_NOT_S)

🔍 Remote MCP Deepwiki

Additional relevant context for reviewing PR #254

  • Repository wiki contains a Command Line Interface user guide and developer testing guidance that are directly relevant to this PR's changes to CLI behaviour, localization, and tests:

    • Wiki sections: "User Guide → Command Line Interface" and "Developer Guide → Testing Framework" (useful for verifying docs and test updates).
  • The repo documents a "Six-Stage Pipeline" and "Module Organization" under Architecture — useful background when assessing whether CLI/config changes interact with manifest parsing, IR generation, or the runner/subcommands.

  • There is a "Code Quality Standards" and CI/CD guidance under Developer Guide which is relevant given the PR adds a compile-time feature gate (serde_json) and many new tests; reviewers should confirm CI will run with the new feature set and test matrix.

Sources:

  • Deepwiki repository structure for leynos/netsuke
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: release / build-macos (aarch64-apple-darwin, macos-15, macos-arm64, macos-aarch64) / Build macos artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: build-test (ubuntu-latest, stable)
🔇 Additional comments (45)
src/cli_policy.rs (1)

20-24: Documentation examples correctly demonstrate locale field initialisation.

Both code examples in the documentation now properly show the locale: None field when constructing a Cli struct. This aligns with the new locale field added in this PR and ensures the examples remain accurate and compilable.

Also applies to: 34-39

src/runner/process/file_io.rs (1)

34-34: Logging messages improved for clarity and idiomaticity.

The wording updates from "Generated...at" to "Wrote...to" make user-facing log output clearer and more consistent with standard English conventions. These minor improvements align with the PR's objective to refine CLI output for clarity.

Also applies to: 87-87

docs/roadmap.md (1)

187-188: Roadmap task marked complete as CLI output refinement is delivered.

The "Refine all CLI output for clarity" task is correctly marked as completed, reflecting the localisation support, Fluent-based message catalogues, and logging improvements delivered in this PR.

src/runner/process/mod.rs (1)

126-129: LGTM!

The wording change from "Running" to "Executing" is consistent with the broader log-message clarity improvements across the runner modules.

src/runner/mod.rs (4)

122-122: LGTM!

The locale: None field addition keeps the doc example in sync with the updated Cli struct definition.


173-177: Improved observability with structured logging.

The structured info! macro with explicit target and subcommand fields provides better filtering and searchability compared to the previous unstructured message.


234-234: LGTM!

Doc example updated to reflect the new locale field.


274-274: LGTM!

Doc example updated to reflect the new locale field.

locales/en-US/messages.ftl (3)

1-6: LGTM!

The CLI about and usage keys are well-structured with appropriate placeholders.


7-14: LGTM!

Subcommand descriptions are clear and action-oriented. The use of "artefacts" at line 9 follows en-GB-oxendict spelling conventions.


19-21: Duplicate message templates are justified, but consider whether distinct error scenarios merit distinct messages.

clap-error-invalid-value and clap-error-value-validation correctly map to distinct clap error kinds: the former applies when a value is not in the set of allowed values, whilst the latter applies when a value fails custom validation or parser logic. Keeping separate message keys is the right choice.

However, both currently use identical templates across all locales. If your users benefit from understanding why validation failed (values disallowed versus values invalid via parser), consider varying the templates. Otherwise, the current approach is acceptable—both represent user-supplied values that failed acceptance checks.

Cargo.toml (3)

8-8: LGTM!

Including locales/** ensures locale resources are packaged with the crate.


60-62: LGTM!

Build-dependencies are correctly specified with SemVer-compatible caret requirements (implicit). The preserve_order feature on serde_json maintains deterministic key ordering during config serialization.


55-55: ortho_config = "0.7.0" is a published version on crates.io and the version specification complies with the SemVer-compatible caret requirements.

docs/execplans/cli-output-clarity.md (2)

22-31: LGTM!

Progress tracking is clear and timestamps follow ISO 8601 format.


78-84: LGTM!

Acronyms DI and BDD are expanded on first use, and the first-person pronoun issue has been resolved.

build.rs (2)

23-24: LGTM!

The LocalizedParseFn type alias clearly documents the expected signature for the localized CLI parsing entry point.


75-80: Excellent compile-time contract enforcement.

These static const assertions validate function signatures at build time, ensuring cli module exports remain compatible with the documented API. The build fails immediately if signatures drift, catching breaking changes early.

docs/users-guide.md (1)

491-506: LGTM!

The Network Policy Options section clearly documents the fetch helper's security controls with wildcard support noted.

docs/netsuke-design.md (1)

2013-2031: LGTM!

The documentation changes correctly describe the new CLI design with OrthoConfig layering and Fluent localisation. The text uses en-GB-oxendict spelling ("localised", "behaviour"), maintains 80-column wrapping, and avoids personal pronouns as required by the coding guidelines.

tests/features/cli.feature (1)

53-58: LGTM!

The updated error message expectation and new Spanish localisation scenario provide good coverage for the locale-aware CLI parsing. The scenario correctly places --locale es-ES before the invalid subcommand, ensuring the locale hint is extracted before clap encounters the error.

src/lib.rs (1)

11-11: LGTM!

Exposing cli_localization publicly enables tests and downstream consumers to build localisers. This aligns with the module's use in main.rs and the BDD test steps.

locales/es-ES/messages.ftl (1)

1-21: LGTM!

The Spanish translations are well-structured and the error message keys align with the clap error formatting expected by the localisation layer. The "Subcomando desconocido" message at line 20 correctly matches the BDD test expectation in cli.feature.

src/main.rs (4)

24-38: Double init_tracing call will panic at runtime.

When merge_with_config fails, init_tracing(Level::ERROR) is called at line 27. However, if it succeeds, init_tracing(max_level) is called at line 38. If the error path is taken first on one invocation and success on another, this is fine. But consider the control flow: the error path returns early, so only one call occurs per execution. However, fmt().init() internally calls set_global_default, which panics if called more than once in the same process.

This is actually safe because the error path returns ExitCode::FAILURE before reaching line 38. Disregard this concern.


12-22: LGTM!

The locale detection flow correctly prioritises CLI --locale over the NETSUKE_LOCALE environment variable. The localiser is built before parsing, ensuring error messages are localised from the outset.


24-31: LGTM!

The config merge error handling correctly initialises tracing at ERROR level before logging, ensuring the failure message is visible. The early return prevents the double-init issue.


49-54: LGTM!

The init_tracing helper centralises subscriber setup. Writing to stderr is appropriate for diagnostic output.

src/cli_localization.rs (3)

1-4: LGTM!

The module documentation clearly describes the purpose and the fallback strategy.


24-34: LGTM!

The Localizer implementation for LayeredLocalizer correctly delegates to the primary localiser first and falls back when the lookup returns None.


63-81: LGTM!

The build_localizer function correctly prioritises the preferred locale, falling back to English when parsing fails or the locale is unsupported. The #[must_use] attribute ensures callers do not discard the result.

tests/bdd/steps/cli.rs (2)

22-31: LGTM!

The updated apply_cli function mirrors the locale-aware parsing flow in main.rs, ensuring BDD tests exercise the same code paths as production. The locale hint extraction and localiser construction are correctly sequenced.


85-87: LGTM!

Removing the mut binding and delegating to with_default_command() is cleaner and aligns with the method's ownership semantics.

src/host_pattern.rs (3)

10-42: LGTM! ValidationContext addresses the string-heavy function arguments alert.

The refactoring groups the original pattern reference into a context struct, reducing parameter repetition across validation calls. This directly addresses the CodeScene alert about 58.3% string arguments.


196-202: LGTM! FromStr implementation is idiomatic.

Delegating to Self::parse ensures consistent behaviour across all string-to-HostPattern conversions.


218-226: LGTM! Deserialize implementation correctly maps parse errors.

Using serde::de::Error::custom to convert HostPatternError preserves the structured error message for downstream consumers.

tests/cli_tests.rs (3)

327-380: LGTM! locale_hint_from_args tests cover the requested edge cases.

These tests address the previous review comment requesting coverage for space form, equals form, trailing flag, double-dash handling, and last-wins precedence.


455-486: LGTM! merge_with_config integration test validates end-to-end precedence.

This test exercises config discovery, environment variables, and CLI merging as requested in the previous review comment.


488-501: LGTM! Spanish localisation test validates error message translation.

The test confirms that invalid subcommand errors are localised correctly.

src/cli.rs (7)

6-19: LGTM! Import organization is clean.

The imports are well-grouped by source crate and support the new localisation and configuration features.


58-66: LGTM! parse_locale validates using LanguageIdentifier.

Delegating to LanguageIdentifier::from_str ensures only valid BCP 47 locale tags are accepted.


78-149: LGTM! Cli struct enhancements for OrthoConfig integration.

The #[ortho_config(...)] attributes correctly configure default handling, merge strategies for list fields, and CLI-default-as-absent semantics for proper layering.


254-276: LGTM! Subcommand localisation avoids unnecessary cloning.

Using std::mem::take to move ownership addresses the previous performance concern about cloning subcommands.


278-305: LGTM! locale_hint_from_args handles edge cases correctly.

The implementation properly handles -- separator, equals form, space form, and last-wins semantics as verified by the corresponding tests.


350-397: LGTM! merge_with_config implements correct layer precedence.

The function composes defaults → file → environment → CLI layers with proper error accumulation. Preserving cli.command after merge is intentional, as noted in the previous review comment.


222-224: Document the usage_body function.

Public utility functions require Rustdoc comments per coding guidelines. Add a /// comment explaining the purpose.

Proposed fix
+/// Extract the body of a usage string, stripping the "Usage: " prefix if present.
 fn usage_body(usage: &str) -> &str {
     usage.strip_prefix("Usage: ").unwrap_or(usage)
 }

Likely an incorrect or invalid review comment.

Comment thread docs/execplans/cli-output-clarity.md Outdated
Comment thread docs/execplans/cli-output-clarity.md Outdated
Comment thread docs/users-guide.md Outdated
Comment thread docs/users-guide.md Outdated
Comment thread src/cli_localization.rs
Comment thread src/cli.rs
Comment thread src/cli.rs
Comment thread src/host_pattern.rs
Comment thread tests/cli_tests.rs Outdated
This change integrates OrthoConfig for layered configuration and Fluent for localized CLI help and error messages. English and Spanish locales are included, with support for the --locale flag and NETSUKE_LOCALE environment variable.

It updates CLI parsing to use localized clap errors, refines user-facing CLI output for clarity, and implements configuration merging respecting OrthoConfig precedence. Comprehensive unit and behavioral tests verify parsing, localization fallback, and network policy enforcement derived from CLI flags.

The extensive test suite replaces the older monolithic CLI tests, introducing modular test files for parsing, locale, merge, and policy coverage.

Documentation is updated to reflect localization support, configuration layering, and refined CLI behaviors.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cli.rs (1)

1-5: File exceeds the 400-line limit (currently 402 lines).

Per coding guidelines, files must not exceed 400 lines. Extract the localisation helpers (localize_command, localize_subcommands, usage_body, locale_hint_from_args) into a dedicated module (e.g., cli_l10n.rs or merge into cli_localization.rs) to bring this file under the threshold.

♻️ Duplicate comments (4)
docs/users-guide.md (1)

488-489: Past spelling concern already addressed.

The documentation now correctly uses "Localize" (en-GB-oxendict -ize form) as requested in previous reviews. This aligns with the coding guidelines.

src/host_pattern.rs (1)

223-235: Serialization no longer clones unnecessarily for non-wildcard patterns.

The previous review feedback has been addressed: non-wildcard patterns now call serializer.serialize_str(&self.pattern) directly without allocation, whilst wildcard patterns allocate only when necessary via format!.

src/cli.rs (2)

336-348: Documentation added as requested in previous review.

The brief doc comments on env_provider and config_discovery address the earlier feedback.


350-353: Documentation added as requested.

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 187011a and 13910b8.

📒 Files selected for processing (16)
  • Cargo.toml
  • build.rs
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md
  • docs/users-guide.md
  • src/cli.rs
  • src/cli_localization.rs
  • src/host_pattern.rs
  • src/lib.rs
  • src/stdlib/network/policy/mod.rs
  • tests/cli_tests/helpers.rs
  • tests/cli_tests/locale.rs
  • tests/cli_tests/merge.rs
  • tests/cli_tests/mod.rs
  • tests/cli_tests/parsing.rs
  • tests/cli_tests/policy.rs
🧰 Additional context used
📓 Path-based instructions (6)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • tests/cli_tests/mod.rs
  • src/lib.rs
  • tests/cli_tests/parsing.rs
  • tests/cli_tests/locale.rs
  • src/host_pattern.rs
  • src/stdlib/network/policy/mod.rs
  • tests/cli_tests/policy.rs
  • tests/cli_tests/merge.rs
  • src/cli.rs
  • build.rs
  • tests/cli_tests/helpers.rs
  • src/cli_localization.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • tests/cli_tests/mod.rs
  • src/lib.rs
  • tests/cli_tests/parsing.rs
  • tests/cli_tests/locale.rs
  • src/host_pattern.rs
  • src/stdlib/network/policy/mod.rs
  • tests/cli_tests/policy.rs
  • tests/cli_tests/merge.rs
  • src/cli.rs
  • build.rs
  • tests/cli_tests/helpers.rs
  • src/cli_localization.rs
Cargo.toml

📄 CodeRabbit inference engine (AGENTS.md)

Cargo.toml: In Rust Cargo.toml, use explicit version ranges and keep dependencies up-to-date.
All crate versions specified in Cargo.toml must use SemVer-compatible caret requirements (e.g., some-crate = "1.2.3") to allow safe non-breaking updates.
The use of wildcard (*) or open-ended inequality (>=) version requirements in Cargo.toml is strictly forbidden.
Tilde requirements (~) in Cargo.toml should only be used where a dependency must be locked to patch-level updates for a specific, documented reason.

Files:

  • Cargo.toml
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: When new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve, proactively update the relevant file(s) in the docs/ directory to reflect the latest state.
Documentation must use en-GB-oxendict spelling and grammar ("-ize" / "-yse" / "-our"), with exception for the LICENSE filename.

docs/**/*.md: Use British English (en-GB) spelling with -ize endings (realize, organization), -lyse endings (analyse, paralyse, catalyse), -our endings (colour, behaviour), -re endings (calibre, centre, fibre), double 'l' (cancelled, counsellor), maintained 'e' (likeable, liveable), and -ogue endings (analogue, catalogue)
Use the Oxford comma in documentation: 'ships, planes, and hovercraft'
Treat company names as collective nouns in documentation: 'Concordat Industries are expanding'
Write headings in sentence case in documentation
Use Markdown headings (#, ##, ###) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Provide code blocks and lists using standard Markdown syntax
Always provide a language identifier for fenced code blocks; use plaintext for non-code text
Use - as the first level bullet and renumber lists when items change in documentation
Prefer inline links using [text](url) or angle brackets around the URL in documentation
Ensure blank lines before and after bulleted lists and fenced blocks in documentation
Ensure tables have a delimiter line below the header row in documentation
Expand any uncommon acronym on first use in documentation (e.g., Continuous Integration (CI))
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use GitHub-flavoured numeric footnotes referenced as [^1] in documentation
Number footnotes in order of appearance in the document
Caption every table and every diagram in documentation
Use ![alt text](path/to/image) for embedding figures with brief alt te...

Files:

  • docs/users-guide.md
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown must be wrapped at 120 columns.
Tables and headings in Markdown must not be wrapped.
Use dashes (-) for list bullets in Markdown.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/users-guide.md
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/users-guide.md
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md
docs/**/{README,readme,GUIDE,guide,*.md}

📄 CodeRabbit inference engine (docs/adr-001-replace-serde-yml-with-serde-saphyr.md)

Document in Netsuke's README and user guide that the project now supports YAML 1.2 (not YAML 1.1) and that duplicate keys in manifests are no longer permitted

Files:

  • docs/users-guide.md
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md
docs/**/!(README).md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

Avoid first and second person personal pronouns outside the README.md file in documentation

Files:

  • docs/users-guide.md
  • docs/execplans/cli-output-clarity.md
  • docs/netsuke-design.md
🧠 Learnings (1)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • tests/cli_tests/mod.rs
  • src/lib.rs
  • tests/cli_tests/parsing.rs
  • tests/cli_tests/locale.rs
  • src/host_pattern.rs
  • src/stdlib/network/policy/mod.rs
  • tests/cli_tests/policy.rs
  • tests/cli_tests/merge.rs
  • src/cli.rs
  • build.rs
  • tests/cli_tests/helpers.rs
  • src/cli_localization.rs
🧬 Code graph analysis (5)
tests/cli_tests/mod.rs (1)
src/stdlib/network/mod.rs (1)
  • policy (360-360)
tests/cli_tests/locale.rs (3)
tests/cli_tests/helpers.rs (1)
  • os_args (5-7)
src/cli.rs (2)
  • locale_hint_from_args (282-307)
  • parse_with_localizer_from (317-334)
src/cli_localization.rs (1)
  • build_localizer (68-85)
tests/cli_tests/policy.rs (3)
src/cli.rs (1)
  • default (168-182)
src/stdlib/network/policy/mod.rs (2)
  • default (323-325)
  • evaluate (286-319)
src/host_pattern.rs (1)
  • parse (176-182)
tests/cli_tests/merge.rs (2)
src/cli.rs (2)
  • default (168-182)
  • merge_with_config (361-402)
test_support/src/env_lock.rs (1)
  • acquire (24-29)
src/cli.rs (2)
src/host_pattern.rs (2)
  • matches (184-196)
  • new (33-35)
tests/cli_tests/parsing.rs (1)
  • default (26-43)
🪛 LanguageTool
docs/users-guide.md

[uncategorized] ~488-~488: Loose punctuation mark.
Context: ...e logging output. - --locale <LOCALE>: Localize CLI help and error messages (f...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~496-~496: Loose punctuation mark.
Context: ...ions: - --fetch-allow-scheme <SCHEME>: Allow additional URL schemes beyond the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~499-~499: Loose punctuation mark.
Context: ...defaults. - --fetch-allow-host <HOST>: Allow the provided hostnames when defau...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~502-~502: Loose punctuation mark.
Context: ...pported). - --fetch-block-host <HOST>: Always block the provided hostnames (wi...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~505-~505: Loose punctuation mark.
Context: ...e allowlisted. - --fetch-default-deny: Deny all hosts by default and only perm...

(UNLIKELY_OPENING_PUNCTUATION)

docs/execplans/cli-output-clarity.md

[uncategorized] ~105-~105: Possible missing comma found.
Context: ... explicit handling for missing required values and make sure clap defaults do not i...

(AI_HYDRA_LEO_MISSING_COMMA)


[grammar] ~109-~109: The word ‘help’ is a conjunction. In formal texts, use “to”.
Context: ...where needed). 3. Localize CLI help and clap errors. Create Fluent resources (f...

(HELP_AND_VB)


[uncategorized] ~188-~188: Loose punctuation mark.
Context: ... and config layering. - make check-fmt, make lint, and make test pass. - `d...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~198-~198: Consider using a different verb for a more formal wording.
Context: ... error output. - If tests fail mid-run, fix the underlying issue and re-run the sam...

(FIX_RESOLVE)


[uncategorized] ~207-~207: Possible missing comma found.
Context: ...tmp/netsuke-help.log`). - A failing CLI invocation showing localized error output (record ...

(AI_HYDRA_LEO_MISSING_COMMA)

🔍 Remote MCP Deepwiki

Additional context gathered (relevant to reviewing PR #254)

  • Repository docs/wiki confirm CLI/user-guide, testing, and CI expectations that PR touches:

    • CLI uses clap; default command is build; man page generated by build.rs — verify build.rs changes keep man generation CI-friendly and SOURCE_DATE_EPOCH handling.
    • Testing matrix includes unit, snapshot (insta), BDD (cucumber) and integration tests; CI runs cargo test --all-features and treats warnings as errors — new tests/localization must pass existing CI gates.
    • Test infrastructure uses cap-std/camino for filesystem, and strict clippy rules; changes adding ortho_config and serde_json feature should not break lint/format/test policies.
  • Manifest/template/templating behavior and expectations (important since PR adds localization + ortho_config):

    • Manifest parsing is two-pass: structural expansion (foreach/when) then deserialization + string rendering via minijinja; custom functions (env, glob) and strict undefined behavior are used — ensure localization hooks and OrthoConfig merging integrate with this pipeline without changing rendering order.
    • glob/env functions and cap-std/camino constraints exist; tests rely on deterministic ordering and snapshot stability — new locale files and CLI flow must preserve determinism used by insta snapshots.
  • IR / Ninja generation and security expectations (relevant because CLI/localization affects error messages and man page text):

    • Commands are shell-escaped via shell-quote and validated with shlex; multi-line scripts are encoded for printf %b wrapper — localization must not introduce unescaped content into command paths/messages.
    • Generated Ninja and snapshots must remain deterministic (sorted actions/edges); adding locale resources or ortho_config features must not change ordering of IR/Ninja outputs used in tests.
  • Build, CI, and release constraints that reviewers should check:

    • CI runs formatting, clippy deny-warnings, and full tests on stable + MSRV (1.89.0). New Cargo.toml defaults/features (serde_json, ortho_config) must not break MSRV or clippy.
    • build.rs produces the man page and uses SOURCE_DATE_EPOCH for reproducible builds — ensure new type alias and const checks do not alter build script side-effects or cause warnings treated as errors.

Tools used

  • Deepwiki_read_wiki_contents — repository wiki and docs content retrieval.
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-linux (aarch64-unknown-linux-gnu, linux-arm64, arm64) / Build linux artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: release / build-macos (aarch64-apple-darwin, macos-15, macos-arm64, macos-aarch64) / Build macos artefacts
  • GitHub Check: build-test (ubuntu-latest, stable)
🔇 Additional comments (34)
docs/users-guide.md (1)

530-548: Configuration and localization section is clear and complete.

The section accurately describes OrthoConfig discovery order, environment variable conventions, and locale selection. The documentation follows en-GB-oxendict spelling conventions throughout.

docs/netsuke-design.md (2)

1052-1109: API changes accurately documented in the class diagram.

The updated signatures for StdlibConfig, WhichModule, WhichResolver, EnvSnapshot, WhichConfig, and WorkspaceSkipList correctly reflect the new type aliases (OptionalPath, StringList, etc.) and parameter changes introduced in the PR. The diagram maintains consistency with the codebase.


2013-2031: CLI implementation section accurately describes the integration.

The documentation clearly explains OrthoConfig layering, locale selection via --locale or NETSUKE_LOCALE, configuration discovery order, and environment variable conventions. This aligns with the implementation changes across the PR.

src/lib.rs (1)

8-8: New localization module correctly exposed.

The pub mod cli_localization declaration appropriately exports the localization functionality for use in main.rs and tests. Placement between cli and cli_policy is logical and follows the module organization pattern.

tests/cli_tests/helpers.rs (1)

5-7: Helper function is clear and appropriate.

The os_args function provides a straightforward conversion for test arguments. The pub(super) visibility correctly restricts access to the test module hierarchy, and the implementation is concise and correct.

tests/cli_tests/locale.rs (8)

1-1: Module documentation is clear and appropriate.

The module-level doc comment succinctly describes the module's purpose.


3-8: Imports are well-organized.

All imports are necessary and correctly scoped for test usage.


10-19: Test logic is correct and well-structured.

The test validates space-form locale parsing with clear diagnostics via ensure!.


21-30: Test validates equals-form parsing correctly.

The test complements the space-form test and maintains consistent structure.


32-41: Edge case handling is properly validated.

The test correctly verifies that a trailing --locale flag without a value yields None.


43-52: Double-dash terminator behaviour is correctly validated.

The test ensures arguments after -- are properly ignored during locale hint extraction.


54-63: Last-flag precedence is correctly validated.

The test ensures that when multiple --locale flags are provided, the last one takes precedence.


65-79: Spanish localization integration is properly tested.

The test validates end-to-end localized error messaging by building a Spanish localizer and confirming the error contains "Subcomando desconocido".

docs/execplans/cli-output-clarity.md (6)

1-8: Documentation opening is correct and well-formatted.

The title uses proper en-GB-oxendict spelling with "-ized" form, and the living document note is appropriately wrapped.


9-31: Purpose and progress sections are clear and actionable.

The purpose statement clearly defines success criteria, and the progress checklist tracks completion effectively.


38-77: Decision log and context sections provide clear guidance.

The decision log captures rationales for OrthoConfig and localization choices, whilst the context section properly references relevant files and documentation.


78-143: Testing guidance and plan of work are comprehensive.

Acronyms are properly expanded on first use, the plan is detailed and actionable, and en-GB-oxendict spelling is consistently applied throughout.


144-191: Concrete steps and validation criteria are clear and executable.

The shell commands follow best practices with pipefail and tee, and validation criteria are measurable and comprehensive.


192-233: Closing sections complete the ExecPlan effectively.

Idempotence guidance, artifact requirements, and interface specifications are all clearly documented, with consistent en-GB-oxendict spelling throughout.

Cargo.toml (3)

8-8: Locale resources correctly included in package.

The addition of locales/** to the include list ensures localization resources are distributed with the package.


56-56: OrthoConfig dependency version is correct.

The version specification uses implicit caret semantics as permitted by the coding guidelines.


61-63: Build dependencies are correctly specified.

The additions of ortho_config, serde, and serde_json to build-dependencies support the build-time localization and type handling introduced in build.rs.

src/stdlib/network/policy/mod.rs (3)

11-11: HostCandidate import is correct.

The import addition properly brings the new wrapper type into scope for the matching calls below.


298-306: Blocked-hosts matching correctly updated.

The change wraps the host string in HostCandidate to match the updated HostPattern::matches signature, improving type safety as per the newtype pattern.


308-316: Allowlist matching consistently updated.

The change mirrors the blocked-hosts update, ensuring consistent usage of HostCandidate across both policy checks.

tests/cli_tests/policy.rs (5)

1-8: Module documentation and imports are appropriate.

The module doc clearly describes the test scope, and imports are correctly organized.


10-30: Default HTTPS policy is correctly validated.

The test verifies that the default policy permits HTTPS whilst rejecting HTTP with the appropriate SchemeNotAllowed error.


32-57: Default-deny allowlist behaviour is thoroughly tested.

The test validates that default-deny mode permits only allowlisted hosts and rejects others with HostNotAllowlisted.


59-83: Blocklist precedence is correctly validated.

The test confirms that blocklist entries override allowlist entries and validates both the error variant and error message text.


85-96: Invalid scheme rejection is properly tested.

The test validates that schemes starting with digits are rejected with an appropriate error message.

src/host_pattern.rs (2)

10-27: Newtypes successfully reduce string-heavy function arguments.

The introduction of HostPatternInput<'a> and HostCandidate<'a> newtypes addresses the CodeScene flag about string-heavy function arguments. By wrapping &str in domain-specific types, you've improved type safety and reduced primitive obsession whilst making function signatures more self-documenting.


28-61: ValidationContext successfully refactors validation logic.

Moving validation logic into ValidationContext::validate_label reduces string parameters from the original validate_label(label, original) to self.validate_label(label). This captures the original pattern for error messages within the context, improving the design and contributing to the resolution of the string-heavy arguments issue.

src/cli.rs (2)

256-278: The cloning concern from the previous review has been addressed.

The use of std::mem::take to extract, modify, and reassign each subcommand avoids the unnecessary clone that was previously flagged.


309-334: Well-structured public API with proper error localisation.

The function correctly localizes both the command and any parsing errors. The documentation is complete with an # Errors section as expected for fallible public APIs.

Comment thread build.rs Outdated
Comment thread Cargo.toml Outdated
Comment thread src/cli.rs Outdated
Comment thread src/cli.rs
Comment thread tests/cli_tests/merge.rs
Comment thread tests/cli_tests/mod.rs Outdated
- Moved localization helpers and related functions from `src/cli.rs` to new module `src/cli_l10n.rs`.
- Updated `build.rs` and `src/lib.rs` to include the new module.
- Simplified `cli.rs` by re-exporting and using functions from `cli_l10n`.

This improves code organization by separating localization concerns from CLI definitions.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Refine CLI output localisation with OrthoConfig and tests Refine CLI output clarity with OrthoConfig localisation and tests Jan 2, 2026
These tests validate OrthoConfig layer precedence including defaults, file, env, CLI, list-value appending, and user-provided override extraction. Added additional documentation comments to test modules for clarity and maintenance.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 3, 2026

@coderabbitai Have the following now been resolved?

Please address the comments from this code review:

## Overall Comments
- In the ExecPlan section that specifies adding `ortho_config = "0.7.0"`, consider referencing the existing dependency management conventions (e.g., workspace-wide versions or a tooling file) instead of a hardcoded example version so the document doesn’t drift from the actual Cargo.toml state.
- Where you describe new Fluent resources (e.g., `locales/en-US/messages.ftl`), it would help to explicitly tie this to any existing i18n/locale directory layout in the repo or to state that this is a new convention, so future implementers don’t accidentally introduce a parallel structure.

## Individual Comments

### Comment 1
<location> `docs/execplans/cli-output-clarity.md:69` </location>
<code_context>
+for CLI behaviour are in `docs/netsuke-design.md` and the roadmap entry in
+`docs/roadmap.md` (Phase 3 → “CLI and Feature Completeness”).
+
+Testing guidance for fixtures, DI, and BDD lives in:
+
+- `docs/rust-testing-with-rstest-fixtures.md`
</code_context>

<issue_to_address>
**suggestion (review_instructions):** DI and BDD are acronyms that are not expanded when first mentioned.

Consider expanding these acronyms on first use, for example: "dependency injection (DI)" and "behaviour-driven development (BDD)", so readers are not expected to infer their meaning from context.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.md`

**Instructions:**
Define uncommon acronyms on first use.

</details>
</issue_to_address>

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 3, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the ExecPlan document to check if review comments have been addressed
cat docs/execplans/cli-output-clarity.md

Length of output: 10872


@leynos: I've reviewed the current state of docs/execplans/cli-output-clarity.md. Here's the status of the three review comments:

✅ Resolved

Comment 3 (DI and BDD acronyms): This has been addressed. Line 69 area now reads:

Testing guidance for fixtures, dependency injection (DI), and behaviour-driven development (BDD) lives in:

Both acronyms are properly expanded on first use.

❌ Not Resolved

Comment 1 (Hardcoded ortho_config version): The "Interfaces and Dependencies" section still contains:

Add ortho_config as a dependency using a caret version (for example, ortho_config = "0.7.0"), enabling yaml/json5 features only if required...

The hardcoded 0.7.0 example remains. Consider rephrasing to reference the actual dependency management approach, for example: "Add ortho_config as a dependency at the version specified in Cargo.toml" or similar.

Comment 2 (Fluent resources directory convention): Step 3 under "Plan of Work" mentions:

Create Fluent resources (for example locales/en-US/messages.ftl and a CLI-specific bundle)...

This doesn't clarify whether locales/ is a new convention being established or ties to an existing i18n directory layout. Consider adding a sentence like "This establishes locales/ as the standard i18n directory structure for the project" or "This follows the existing locale convention in locales/".

Summary: One of three issues has been resolved; two remain outstanding.

…cumentation

- Improve instructions on setting up Fluent localization, emphasizing following the existing locales/ layout.
- Refine instructions for wiring FluentLocalizer before parsing CLI and handling errors.
- Update dependency addition instructions to refer to the version in Cargo.toml rather than specifying a caret version explicitly.
- Ensure documentation reflects current best practices for CLI output clarity and dependencies.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a92741 and 63743d5.

📒 Files selected for processing (6)
  • build.rs
  • docs/execplans/cli-output-clarity.md
  • src/cli.rs
  • src/lib.rs
  • tests/cli_tests/merge.rs
  • tests/cli_tests/mod.rs
🧰 Additional context used
📓 Path-based instructions (5)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • src/lib.rs
  • tests/cli_tests/mod.rs
  • build.rs
  • tests/cli_tests/merge.rs
  • src/cli.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • src/lib.rs
  • tests/cli_tests/mod.rs
  • build.rs
  • tests/cli_tests/merge.rs
  • src/cli.rs
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: When new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve, proactively update the relevant file(s) in the docs/ directory to reflect the latest state.
Documentation must use en-GB-oxendict spelling and grammar ("-ize" / "-yse" / "-our"), with exception for the LICENSE filename.

docs/**/*.md: Use British English (en-GB) spelling with -ize endings (realize, organization), -lyse endings (analyse, paralyse, catalyse), -our endings (colour, behaviour), -re endings (calibre, centre, fibre), double 'l' (cancelled, counsellor), maintained 'e' (likeable, liveable), and -ogue endings (analogue, catalogue)
Use the Oxford comma in documentation: 'ships, planes, and hovercraft'
Treat company names as collective nouns in documentation: 'Concordat Industries are expanding'
Write headings in sentence case in documentation
Use Markdown headings (#, ##, ###) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Provide code blocks and lists using standard Markdown syntax
Always provide a language identifier for fenced code blocks; use plaintext for non-code text
Use - as the first level bullet and renumber lists when items change in documentation
Prefer inline links using [text](url) or angle brackets around the URL in documentation
Ensure blank lines before and after bulleted lists and fenced blocks in documentation
Ensure tables have a delimiter line below the header row in documentation
Expand any uncommon acronym on first use in documentation (e.g., Continuous Integration (CI))
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use GitHub-flavoured numeric footnotes referenced as [^1] in documentation
Number footnotes in order of appearance in the document
Caption every table and every diagram in documentation
Use ![alt text](path/to/image) for embedding figures with brief alt te...

Files:

  • docs/execplans/cli-output-clarity.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown must be wrapped at 120 columns.
Tables and headings in Markdown must not be wrapped.
Use dashes (-) for list bullets in Markdown.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/execplans/cli-output-clarity.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/execplans/cli-output-clarity.md
docs/**/{README,readme,GUIDE,guide,*.md}

📄 CodeRabbit inference engine (docs/adr-001-replace-serde-yml-with-serde-saphyr.md)

Document in Netsuke's README and user guide that the project now supports YAML 1.2 (not YAML 1.1) and that duplicate keys in manifests are no longer permitted

Files:

  • docs/execplans/cli-output-clarity.md
docs/**/!(README).md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

Avoid first and second person personal pronouns outside the README.md file in documentation

Files:

  • docs/execplans/cli-output-clarity.md
🧠 Learnings (1)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • src/lib.rs
  • tests/cli_tests/mod.rs
  • build.rs
  • tests/cli_tests/merge.rs
  • src/cli.rs
🧬 Code graph analysis (4)
tests/cli_tests/mod.rs (1)
src/stdlib/network/mod.rs (1)
  • policy (360-360)
build.rs (2)
src/cli_l10n.rs (1)
  • locale_hint_from_args (68-93)
src/cli.rs (2)
  • merge_with_config (280-321)
  • parse_with_localizer_from (234-251)
tests/cli_tests/merge.rs (1)
src/cli.rs (3)
  • default (170-184)
  • parse_with_localizer_from (234-251)
  • merge_with_config (280-321)
src/cli.rs (1)
src/cli_l10n.rs (2)
  • locale_hint_from_args (68-93)
  • localize_command (14-40)
🪛 LanguageTool
docs/execplans/cli-output-clarity.md

[uncategorized] ~105-~105: Possible missing comma found.
Context: ... explicit handling for missing required values and make sure clap defaults do not i...

(AI_HYDRA_LEO_MISSING_COMMA)


[grammar] ~109-~109: The word ‘help’ is a conjunction. In formal texts, use “to”.
Context: ...where needed). 3. Localize CLI help and clap errors. Create Fluent resources (f...

(HELP_AND_VB)


[uncategorized] ~189-~189: Loose punctuation mark.
Context: ... and config layering. - make check-fmt, make lint, and make test pass. - `d...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~199-~199: Consider using a different verb for a more formal wording.
Context: ... error output. - If tests fail mid-run, fix the underlying issue and re-run the sam...

(FIX_RESOLVE)


[uncategorized] ~208-~208: Possible missing comma found.
Context: ...tmp/netsuke-help.log`). - A failing CLI invocation showing localized error output (record ...

(AI_HYDRA_LEO_MISSING_COMMA)

🔍 Remote MCP

I'll help you gather additional context for reviewing this PR. Let me search for information about the key libraries and patterns being used.Based on my research, I've gathered relevant context about the key technologies used in this PR. Let me provide a concise summary of findings that are directly applicable to reviewing this PR.

Summary of Key Findings for PR Review

Fluent Localization (FTL Format)

FTL is a localization file format designed to be simple to read while allowing complex concepts from natural languages like gender, plurals, and conjugations. The PR's message files (locales/en-US/messages.ftl, locales/es-ES/messages.ftl) follow this standard approach.

Best Practice Validation Points:

  • All attributes of messages in the reference language (en-US) must be present in localizations, enforced by tools that warn on missing or obsolete attributes. This is relevant for verifying that the Spanish translations are complete.
  • In FTL files, indentation is part of the syntax; incorrect indentation will lead to parsing errors. The .ftl files should be verified for consistent indentation.

Clap Localization Patterns

Standard clap localization approaches include: replacing hard-coded strings in help templates (e.g., "Usage") with localized versions via Command::help_template, and using custom formatters for error messages. The PR's src/cli_l10n.rs implements similar patterns with the localize_command function.

Configuration Merge Pattern:
A common layered config approach involves: getting all matches from clap, removing default values to identify overrides, calling merge with parsed arguments using original matches, adding other layers (TOML, environment variables), and deserializing into the config struct. This aligns with the PR's merge_with_config function design.

Configuration Layering Standard

Layered configuration is a established pattern in Rust: Hierarchical merging supports layering configurations, ensuring CLI arguments override environment variables, which in turn override file-based configurations. The PR implements this correctly with the precedence order: defaults → file → environment → CLI.

⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-linux (aarch64-unknown-linux-gnu, linux-arm64, arm64) / Build linux artefacts
  • GitHub Check: release / build-macos (aarch64-apple-darwin, macos-15, macos-arm64, macos-aarch64) / Build macos artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: Sourcery review
  • GitHub Check: build-test (ubuntu-latest, stable)
  • GitHub Check: build-test (ubuntu-latest, nightly, true)
🔇 Additional comments (10)
tests/cli_tests/mod.rs (1)

1-9: LGTM! Clean test module structure.

The module documentation is accurate and the submodule organisation is clear and follows standard conventions.

src/lib.rs (1)

11-12: LGTM! Module declarations follow standard patterns.

The private cli_l10n module and public cli_localization module are declared correctly and align with the localisation infrastructure introduced in this PR.

docs/execplans/cli-output-clarity.md (1)

1-234: LGTM! ExecPlan document is comprehensive and well-structured.

The document follows the established format, uses correct en-GB-oxendict spelling throughout, and provides clear guidance for CLI output refinement and localisation. Previous review concerns have been addressed.

tests/cli_tests/merge.rs (3)

19-44: LGTM! Clear test validating default value extraction.

The test correctly verifies that default values are not treated as user-provided CLI overrides. Error context and assertion messages are clear and helpful.


46-90: LGTM! Comprehensive test of layer precedence and list appending.

The test uses distinct values for each layer (jobs: 1→2→3→4; schemes: https→http→ftp→git), making it easy to verify correct precedence and list-appending behaviour. Well-designed test.


92-124: LGTM! Integration test correctly uses environment guards.

The test properly uses EnvLock and EnvVarGuard from test_support for safe environment variable manipulation, complying with Rust 2024 environment safety guidelines. The test validates that environment variables override file config when CLI values are absent.

build.rs (4)

3-10: LGTM! Import additions support localised parsing.

The addition of ArgMatches and reorganisation of imports are appropriate for the new localisation and configuration merge checks.


18-19: LGTM! Module declaration follows established patterns.

The cli_l10n module declaration with path attribute is consistent with the existing cli and host_pattern module declarations in this build script.


26-27: LGTM! Type alias correctly captures localised parse signature.

The LocalizedParseFn type alias accurately represents the signature of parse_with_localizer_from, enabling the const check at line 82 to verify the function remains linked.


78-84: LGTM! Const checks ensure shared symbols remain linked.

The const expressions correctly reference the locale hint extraction, config merge, localised parsing, and host pattern functions, ensuring these symbols remain linked when the build script is compiled without tests.

Comment thread build.rs Outdated
Comment thread src/cli.rs
Comment thread src/cli.rs
Comment thread src/cli.rs
Comment thread src/lib.rs Outdated
- Remove default values from CLI override extraction to prevent false positives.
- Implement `cli_overrides_from_matches` to keep only flags explicitly set via command line.
- Adjust tests accordingly to reflect updated override behavior.
- Remove serde_json from default Cargo features and enable it explicitly in ortho_config deps.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 4, 2026

@coderabbitai Have the following now been resolved?

❌ Not Resolved

Comment 1 (Hardcoded ortho_config version): The "Interfaces and Dependencies" section still contains:

Add ortho_config as a dependency using a caret version (for example, ortho_config = "0.7.0"), enabling yaml/json5 features only if required...

The hardcoded 0.7.0 example remains. Consider rephrasing to reference the actual dependency management approach, for example: "Add ortho_config as a dependency at the version specified in Cargo.toml" or similar.

Comment 2 (Fluent resources directory convention): Step 3 under "Plan of Work" mentions:

Create Fluent resources (for example locales/en-US/messages.ftl and a CLI-specific bundle)...

This doesn't clarify whether locales/ is a new convention being established or ties to an existing i18n directory layout. Consider adding a sentence like "This establishes locales/ as the standard i18n directory structure for the project" or "This follows the existing locale convention in locales/".

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 4, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the ExecPlan document to check if the two review comments have been addressed
cat docs/execplans/cli-output-clarity.md

Length of output: 10918


@leynos: Both issues have now been resolved! ✅

✅ Comment 1 (Hardcoded ortho_config version)

The "Interfaces and Dependencies" section now reads:

Add ortho_config as a dependency at the version specified in Cargo.toml, enabling yaml/json5 features only if required and documenting the decision in docs/netsuke-design.md.

The hardcoded "0.7.0" example has been removed and replaced with a reference to the actual Cargo.toml, as suggested.

✅ Comment 2 (Fluent resources directory convention)

Step 3 in the "Plan of Work" section now includes:

Localise CLI help and clap errors. Create Fluent resources (for example locales/en-US/messages.ftl and a CLI-specific bundle) and wire a FluentLocalizer into CLI parsing. Follow the existing locales/ layout for project translations. Use command().localize(&localizer) before parsing...

The added sentence clarifies that locales/ follows an existing convention rather than establishing a new one.

Summary: All previously unresolved documentation issues have been addressed.

@leynos leynos merged commit f9ac4e1 into main Jan 4, 2026
16 checks passed
@leynos leynos deleted the terragon/refine-cli-output-clarity-cuftfl branch January 4, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant