cli/serviceability: rewrite location get to rfc-20 conforming pattern#3757
Conversation
5f73c25 to
c7133f3
Compare
2fb2f5a to
8d806a7
Compare
|
Today Can we either mirror the |
f2a46ac to
475a322
Compare
8d806a7 to
5056078
Compare
…3753) ## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | **1** | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | 2 | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | 4 | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | 6 | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | 7 | [#3759](#3759) | move per-resource subcommand wrappers into the module crate | | 8 | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | 9 | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3753** — position **1** of 9. Previous: (none — base is `main`) · Next: [#3754](#3754) --- ## Summary of Changes - Adds `doublezero-cli-core` (`crates/doublezero-cli-core/`), the shared library crate every `doublezero-<module>-cli` will reuse per [RFC-20](../rfcs/rfc20-cli-standardization.md). Ships `CliContext` + `CliContextBuilder`, `RequirementCheck` bitflags (bit values aligned with the legacy `CHECK_ID_JSON | CHECK_BALANCE | CHECK_FOUNDATION_ALLOWLIST` constants), the shared validators (`validate_pubkey`, `validate_pubkey_or_code`, `validate_code`, `validate_parse_bandwidth`, `validate_parse_delay_ms`, `validate_parse_jitter_ms`, `validate_parse_delay_override_ms`), the `DisplayVec` formatter, a `tracing` + `tracing-subscriber` `init_logging(verbosity)` helper that writes to stderr, and `testing` helpers (`cli_context_for_tests`, `cli_context_default_for_tests`). - Adds `solana_l1_rpc_url` to `doublezero-config::NetworkConfig` with the per-environment defaults from RFC-20 §Environments (mainnet-beta -> Solana mainnet-beta; testnet and devnet -> Solana testnet; local -> `http://localhost:8899`) plus a `DZ_SOLANA_RPC_URL` env-var override mirroring the existing `DZ_LEDGER_RPC_URL` / `DZ_LEDGER_WS_RPC_URL` overrides. - Migrates the shared `validators.rs` and `formatters.rs` out of `smartcontract/cli/` into the new core crate. Existing import paths continue to compile via thin `pub use` re-export shims in `smartcontract/cli/src/{validators,formatters}.rs`, so the rest of the workspace is unaffected. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Core logic | 7 | +618 / -0 | +618 | | Tests | 1 | +64 / -0 | +64 | | Scaffolding | 4 | +50 / -167 | -117 | | Config/build | 3 | +33 / -0 | +33 | | Generated | 1 | +20 / -0 | +20 | | Docs | 1 | +2 / -1 | +1 | | **Total** | 17 | +787 / -168 | +619 | Introduces ~620 lines of shared CLI utility code in the new core crate while shrinking `smartcontract/cli` by replacing its validator and formatter implementations with thin re-export shims; no behavior change. <details> <summary>Key files (click to expand)</summary> - `crates/doublezero-cli-core/src/context.rs` - `CliContext`, `OutputFormat`, and the `CliContextBuilder` that resolves `--env` defaults from `doublezero-config` and applies per-field overrides. - `crates/doublezero-cli-core/src/validators.rs` - shared `clap` value-parsers (pubkey, code, pubkey-or-code, bandwidth, delay, jitter, delay-override) with their unit tests; moved verbatim from `smartcontract/cli/src/validators.rs`. - `crates/doublezero-cli-core/src/requirements.rs` - `RequirementCheck` bitflags type (KEYPAIR / BALANCE / FOUNDATION_ALLOWLIST) with bit values preserved for ABI continuity with the legacy `u8` constants. - `crates/doublezero-cli-core/src/testing.rs` - `cli_context_for_tests()` / `cli_context_default_for_tests()` helpers for module-crate verb tests. - `crates/doublezero-cli-core/src/formatters.rs` - `DisplayVec` + `stringify_vec` moved from `smartcontract/cli`. - `crates/doublezero-cli-core/src/error.rs` - `Result` alias, `CliError`, `render_eyre` helper for chain-of-causes rendering. - `crates/doublezero-cli-core/src/logging.rs` - `init_logging(verbosity)` via `tracing-subscriber` with stderr writer; honors `RUST_LOG` when set. - `config/src/env.rs` - adds `solana_l1_rpc_url` to `NetworkConfig`, wires it through per environment, and adds `DZ_SOLANA_RPC_URL` override plus tests. </details> ## Testing Verification - `cargo test -p doublezero-cli-core` passes (16 tests across validators, requirements bitflags, context builder, testing helpers, formatters). - `cargo test -p doublezero-config` passes (9 tests including two new ones covering the Solana L1 URL resolution per environment and the `DZ_SOLANA_RPC_URL` override). - `make rust-test` green, including the program-accounts-compat run. - `make rust-lint` clean. - Verified existing `smartcontract/cli` consumers continue to compile against the shim files (`use doublezero_cli::validators::*` and friends resolve through the re-export).
475a322 to
5e5f2df
Compare
5056078 to
dfe9382
Compare
## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | 1 | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | **2** | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | 4 | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | 6 | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | 7 | [#3759](#3759) | move per-resource subcommand wrappers into the module crate | | 8 | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | 9 | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3754** — position **2** of 9. Previous: [#3753](#3753) · Next: [#3755](#3755) --- ## Summary of Changes - Adds the `--solana-url <SOLANA_RPC_URL>` global flag to `doublezero` per RFC-20 §Global flags. Distinct from `--url`, which continues to override the DZ ledger transport; `--solana-url` targets the Solana L1 transport. The flag is parsed and exposed on the binary's `App` struct; per-verb consumption lands when verbs migrate to construct typed Solana L1 clients from `CliContext` (follow-up PRs). - Adds the `--verbose` / `-v` (repeatable) global flag and initializes the `tracing` subscriber at startup via `doublezero_cli_core::init_logging(verbosity)`. Default level is `warn`; `-v` raises to `debug`, `-vv` to `trace`. Honors the `RUST_LOG` env var when set. Diagnostic logs go to stderr so `--json` output on stdout remains parseable. - Replaces the `println!("using keypair: ...")` startup line with a `tracing::info!` event so the keypair confirmation now appears only at `-v` or higher and no longer pollutes parseable stdout. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Core logic | 1 | +13 / -1 | +12 | | Config/build | 2 | +3 / -0 | +3 | | Docs | 1 | +2 / -0 | +2 | | **Total** | 4 | +18 / -1 | +17 | Three new global flags wired into the binary and the logging facade; no changes to subcommand dispatch or verb behavior. <details> <summary>Key files (click to expand)</summary> - `client/doublezero/src/main.rs` - adds `solana_url` and `verbose` fields to the `App` struct, calls `doublezero_cli_core::init_logging(app.verbose)` first thing in `main`, and replaces the `println!` keypair confirmation with `tracing::info!`. - `client/doublezero/Cargo.toml` - depends on `doublezero-cli-core` and `tracing`. </details> ## Testing Verification - `make rust-lint` clean. - `doublezero --help` shows the new `--solana-url` and `--verbose` / `-v` global flags with the expected help text. - `doublezero --keypair /tmp/fake.json --env local -v address` emits a `tracing::info!` event with the keypair path on stderr while stdout shows only the address; no `-v` keeps stderr empty. - Built on top of #3753 (foundation crate); this PR targets `jo/1-cli-core-foundation` and the diff shown is its own contribution only.
5e5f2df to
38ed34b
Compare
dfe9382 to
82adaf7
Compare
## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | 1 | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | 2 | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | **4** | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | 6 | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | 7 | [#3759](#3759) | move per-resource subcommand wrappers into the module crate | | 8 | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | 9 | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3756** — position **4** of 9. Previous: [#3755](#3755) · Next: [#3757](#3757) --- ## Summary of Changes - Renames the `smartcontract/cli/` crate from `doublezero_cli` to `doublezero-serviceability-cli` to satisfy RFC-20's module-crate naming contract (`doublezero-<module>-cli` in kebab-case). The crate stays at `smartcontract/cli/`; only the `[package].name` and `[lib].name` change (lib name is `doublezero_serviceability_cli` because Rust requires underscores in import paths). - Updates all in-tree consumers: workspace `Cargo.toml` dep key, `client/doublezero`, `client/doublezero-geolocation-cli`, `controlplane/doublezero-admin`, and every `use doublezero_cli::` site across all `.rs` files swept to `use doublezero_serviceability_cli::`. - No user-facing command, flag, or output change. External operators who depend on the workspace crate by its old name must update their own `Cargo.toml` and `use` statements. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Scaffolding | 48 | +51 / -51 | 0 | | Config/build | 5 | +6 / -6 | 0 | | Generated | 1 | +51 / -41 | +10 | | Docs | 1 | +1 / -0 | +1 | | **Total** | 53 | +109 / -98 | +11 | Pure mechanical rename of imports and dep keys across the workspace; behavior unchanged. <details> <summary>Key files (click to expand)</summary> - `smartcontract/cli/Cargo.toml` - renames `name = "doublezero_cli"` -> `"doublezero-serviceability-cli"` and `[lib].name` -> `"doublezero_serviceability_cli"`. - `Cargo.toml` (workspace) - renames the workspace dep key. - `client/doublezero/Cargo.toml`, `client/doublezero-geolocation-cli/Cargo.toml`, `controlplane/doublezero-admin/Cargo.toml` - dep + feature-passthrough rename. - All `.rs` files containing `use doublezero_cli::` updated to `use doublezero_serviceability_cli::` (sed sweep across `client/doublezero/src/cli/**`, `client/doublezero/src/command/**`, `controlplane/doublezero-admin/src/**`, `client/doublezero-geolocation-cli/src/**`, and the two binary `main.rs` files). </details> ## Testing Verification - `cargo check --workspace` clean. - `cargo tree -p doublezero` shows `doublezero-serviceability-cli` (and no residual `doublezero_cli`). - `doublezero --version` and `doublezero --env devnet address` continue to work, confirming the binary is unaffected. - Targets `jo/3-cli-context-and-errors`; the diff shown is only this PR's rename.
82adaf7 to
4870936
Compare
… crate (#3759) ## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | 1 | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | 2 | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | 4 | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | 6 | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | **7** | [#3759](#3759) | move per-resource subcommand wrappers into the module crate | | 8 | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | 9 | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3759** — position **7** of 9. Previous: [#3758](#3758) · Next: [#3760](#3760) --- ## Summary of Changes - Moves the 13 per-resource serviceability subcommand wrapper files (`accesspass`, `config`, `contributor`, `device`, `exchange`, `globalconfig`, `link`, `location`, `multicastgroup`, `permission`, `resource`, `tenant`, `user`) from `client/doublezero/src/cli/` into the `doublezero-serviceability-cli` module crate at `smartcontract/cli/src/cli/`, per RFC-20 §Module contract item 2 ("the module crate exports the subcommand enum"). - Adds `smartcontract/cli/src/cli/mod.rs` and `pub mod cli;` in the library's `lib.rs` so the new module is reachable. - Rewrites import paths in the moved files (`doublezero_serviceability_cli::<resource>::*` -> `crate::<resource>::*`) and in the binary (`client/doublezero/src/{cli/command.rs,main.rs}` switch to `doublezero_serviceability_cli::cli::<resource>::*` for the moved types). - `cli/multicast.rs` stays in the binary: its `Subscribe`, `Unsubscribe`, `Publish`, and `Unpublish` variants are async and their `execute` impls live in `client/doublezero/src/command/multicast.rs` (binary-local), depending on `ServiceControllerImpl` and `crate::command::helpers::resolve_client_ip`. The binary's `cli/multicast.rs` now imports `MulticastGroupCliCommand` from the library. - No `Command` enum reshape, no `main.rs` dispatch change. Pure file relocation. The next PR adds the top-level `ServiceabilityCommand` enum; the PR after that wires it into the binary via `#[command(flatten)]` and collapses the dispatch. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Scaffolding | 19 | +75 / -32 | +43 | | Docs | 1 | +1 / -0 | +1 | | **Total** | 20 | +76 / -32 | +44 | Pure file moves (tracked as renames in git, ~95% similarity each) plus import-path rewrites in the binary and the new library `cli/mod.rs`. Behavior unchanged. <details> <summary>Key files (click to expand)</summary> - `smartcontract/cli/src/cli/mod.rs` (new) - declares the 13 moved modules. - `smartcontract/cli/src/lib.rs` - adds `pub mod cli;`. - `client/doublezero/src/cli/mod.rs` - keeps only `command`, `geolocation`, and `multicast` (the binary-local ones). - `client/doublezero/src/cli/command.rs` - imports `MulticastCliCommand` from `crate::cli` and the 13 moved types from `doublezero_serviceability_cli::cli::*`. - `client/doublezero/src/cli/multicast.rs` - imports `MulticastGroupCliCommand` from the library. - `client/doublezero/src/main.rs` - imports the moved subcommand enums (`DeviceCommands`, `LinkCommands`, ...) from `doublezero_serviceability_cli::cli::*`; the per-resource match arms switch from `cli::<resource>::*Commands::*` to `doublezero_serviceability_cli::cli::<resource>::*Commands::*`. </details> ## Testing Verification - `cargo check --workspace` clean. - `make rust-test` green workspace-wide (including the `cargo test -p doublezero-serviceability-cli location::get` reference verb). - `make rust-lint` clean. - `cargo run -p doublezero -- --help` and `cargo run -p doublezero -- device list --help` produce the same command tree as before; the relocation is invisible to users. - Targets `jo/6-docs-cli-standard`; the diff shown is only this PR's contribution. Follow-ups #PR8 (add `ServiceabilityCommand` enum) and #PR9 (flatten in binary + collapse dispatch) complete the RFC-20 §Module contract item 2 work.
## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | 1 | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | 2 | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | 4 | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | **6** | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | 7 | [#3779](#3779) | move per-resource subcommand wrappers into the module crate | | 8 | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | 9 | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3758** — position **6** of 9. Previous: [#3757](#3757) · Next: [#3779](#3779) --- ## Summary of Changes - Adds `docs/cli-standard.md`, the contributor-facing summary of RFC-20 ([rfcs/rfc20-cli-standardization.md](../rfcs/rfc20-cli-standardization.md)). Covers the module contract, argument and output conventions, the global flag set, the diagnostic-logging facade, the preflight `RequirementCheck` bitflags, and walks through `smartcontract/cli/src/location/get.rs` as the worked example. - Updates `CLAUDE.md` with a CLI-standard section pointing at RFC-20, the new contributor doc, and the reference verb so future contributors land on the standard quickly. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Docs | 3 | +253 / -0 | +253 | | **Total** | 3 | +253 / -0 | +253 | Pure documentation: a single new contributor doc plus a short pointer added to `CLAUDE.md` and the CHANGELOG entry recording it. <details> <summary>Key files (click to expand)</summary> - `docs/cli-standard.md` - new file. Roughly 240 lines covering the module contract, argument/output conventions, global flags, logging, the `location get` worked example, the `RequirementCheck` bitflag mapping, authorization rules, and the explicit open follow-ups (Command enum move, geolocation module crate, daemon-control module crate, JSON schema versioning, shell completion). - `CLAUDE.md` - new "CLI Standard (RFC-20)" section between "RFCs and Documentation" and "Style & Terminology" with four bullets pointing at the RFC, the contributor doc, the core crate, and the migration cadence. </details> ## Testing Verification - `make rust-test` green workspace-wide (no code changes; sanity check that the docs commit does not break anything). - Manually previewed the rendered markdown of both `docs/cli-standard.md` and the updated `CLAUDE.md` section for headings, lists, and the code block in the worked example. - Targets `jo/5-cli-location-get-conforming-verb`; the diff shown is only this PR's docs.
…her (#3760) ## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | 1 | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | 2 | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | 4 | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | 6 | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | 7 | [#3779](#3779) | move per-resource subcommand wrappers into the module crate | | **8** | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | 9 | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3760** — position **8** of 9. Previous: [#3779](#3779) · Next: [#3761](#3761) --- ## Summary of Changes - Adds `doublezero_serviceability_cli::cli::ServiceabilityCommand`, the module crate's top-level subcommand enum per RFC-20 §Module contract item 2. - Aggregates 17 serviceability variants: `Init`, `Migrate`, `Address`, `Balance`, `Config`, `GlobalConfig`, `Location`, `Exchange`, `Contributor`, `Permission`, `Tenant`, `Device`, `Link`, `AccessPass`, `User`, `Export`, `Keygen`, `Resource`. - Implements `async fn execute(ctx: &CliContext, client: &impl CliCommand, out: &mut impl Write)` that owns the full per-resource dispatch tree currently inlined in `client/doublezero/src/main.rs`. The `Location::Get` arm forwards `&ctx` and is `.await`ed (matches the RFC-20 reference verb from #3757); all other resource arms are sync. - Not yet wired into the unified binary. The next PR (#9) adds `#[command(flatten)] Serviceability(ServiceabilityCommand)` to the binary's `Command` enum and collapses `main.rs`'s ~270-line match block to a single dispatch arm. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Core logic | 1 | +242 / -0 | +242 | | Scaffolding | 1 | +1 / -0 | +1 | | Docs | 1 | +1 / -0 | +1 | | **Total** | 3 | +244 / -1 | +243 | Single new file in the library plus a one-line `pub mod` in `cli/mod.rs`. The enum is `pub` and reachable but currently has no in-tree consumer; it surfaces as the module crate's public mounting point ready for the binary to flatten. <details> <summary>Key files (click to expand)</summary> - `smartcontract/cli/src/cli/command.rs` (new) - the `ServiceabilityCommand` enum + `async fn execute` dispatcher. Forwards `&CliContext` only to verbs that consume it (today only `LocationCommands::Get` per #3757); other arms ignore `ctx`. The `AccessPassCommands::Fund` arm preserves the existing stdin-reading behavior (`std::io::stdin().lock()`) since that interaction is part of the verb's contract today. - `smartcontract/cli/src/cli/mod.rs` - adds `pub mod command;`. </details> ## Testing Verification - `cargo check --workspace` clean. - `make rust-test` green workspace-wide (no behavior change — the new enum is unused by the binary in this PR). - `make rust-lint` clean. - `cargo doc --no-deps -p doublezero-serviceability-cli` succeeds and the new module appears. - Targets `jo/7-cli-serviceability-move-cli-files`; the diff shown is only this PR's contribution. Final PR #9 will flatten this enum into the binary and collapse `main.rs` dispatch.
## RFC-20 implementation stack This PR is part of a 9-PR chain delivering [RFC-20: CLI standardization](https://github.com/malbeclabs/doublezero/blob/main/rfcs/rfc20-cli-standardization.md). Each PR's diff is **only its own contribution**; reviewers should consume them in order. | # | PR | Scope | |---|----|-------| | 1 | [#3753](#3753) | `doublezero-cli-core` foundation crate + `solana_l1_rpc_url` | | 2 | [#3754](#3754) | `--solana-url` + `--log-verbose` global flags + tracing init | | 3 | [#3755](#3755) | `CliContext` built in `main` + centralized error rendering | | 4 | [#3756](#3756) | rename `doublezero_cli` → `doublezero-serviceability-cli` | | 5 | [#3757](#3757) | rewrite `location get` as the async + `CliContext` reference verb | | 6 | [#3758](#3758) | `docs/cli-standard.md` + `CLAUDE.md` pointer | | 7 | [#3779](#3779) | move per-resource subcommand wrappers into the module crate | | 8 | [#3760](#3760) | add `ServiceabilityCommand` enum + async dispatcher | | **9** | [#3761](#3761) | `#[command(flatten)]` + collapse binary dispatch | **This PR: #3761** — position **9** of 9. Previous: [#3760](#3760) · Next: (none — tip of stack) --- ## Summary of Changes - Hoists `doublezero_serviceability_cli::cli::ServiceabilityCommand` (added in #3760) into the unified `doublezero` binary via `#[command(flatten)]` on the top-level `Command` enum. RFC-20 §Module contract item 2 is now complete: the module crate owns the serviceability subcommand enum, the binary mounts it. - Drops 17 explicit serviceability variants from the binary's `Command` enum: `Init`, `Migrate`, `Address`, `Balance`, `Config`, `GlobalConfig`, `Location`, `Exchange`, `Contributor`, `Permission`, `Tenant`, `Device`, `Link`, `AccessPass`, `User`, `Export`, `Keygen`, `Resource`. They now surface at the top level via the flattened `Serviceability(ServiceabilityCommand)` variant. - Collapses the `main.rs` dispatch match block from roughly 270 lines (the original per-resource explicit dispatch) to about 90 lines, with one new arm doing the work for all serviceability verbs: `Command::Serviceability(cmd) => cmd.execute(&ctx, &client, &mut handle).await`. The remaining arms cover binary-local concerns: daemon-control verbs (`Connect`, `Enable`, `Disable`, `Status`, `Disconnect`, `Latency`, `Routes`), raw-`DZClient` diagnostics (`Account`, `Accounts`, `Log`), the binary-local geolocation tree, `InitGeolocationConfig`, the multicast dispatch (whose `Subscribe`/`Unsubscribe`/`Publish`/`Unpublish` async arms depend on daemon-control infrastructure), and the `Completion` generator. - Re-exports `ServiceabilityCommand` from `smartcontract/cli/src/cli/mod.rs` (`pub use command::ServiceabilityCommand;`) so the binary imports through `doublezero_serviceability_cli::cli::ServiceabilityCommand`. - Updates the version-check skip list (`matches!`) in `main.rs` to match against the flattened variants (`ServiceabilityCommand::Address`, `::Balance`, `::Export`) instead of the now-gone top-level variants. ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |--------------|-------|-------------|------| | Core logic | 2 | +84 / -313 | -229 | | Scaffolding | 1 | +2 / -0 | +2 | | Docs | 1 | +1 / -0 | +1 | | **Total** | 4 | +87 / -313 | -226 | Substantial net deletion in the binary: the 270-line per-resource dispatch in `main.rs` is replaced by one line, and 17 explicit variants in `cli/command.rs` are replaced by one `#[command(flatten)]` variant. <details> <summary>Key files (click to expand)</summary> - `client/doublezero/src/cli/command.rs` - top-level `Command` enum reduces to 14 variants (7 daemon-control + 3 raw-`DZClient` + 1 geolocation + 1 `InitGeolocationConfig` + 1 multicast + 1 completion + 1 flattened serviceability). Adds a doc comment explaining the RFC-20 mounting strategy. - `client/doublezero/src/main.rs` - replaces the ~270-line per-resource match block with binary-stay arms + one `Command::Serviceability(cmd) => cmd.execute(&ctx, &client, &mut handle).await` arm. Imports for the moved subcommand enums (`DeviceCommands`, `LinkCommands`, ...) are gone — only multicast-group enums remain since the binary still dispatches the Group subtree locally. - `smartcontract/cli/src/cli/mod.rs` - `pub use command::ServiceabilityCommand;` so the binary's import path is `doublezero_serviceability_cli::cli::ServiceabilityCommand` (not `::cli::command::ServiceabilityCommand`). </details> ## Testing Verification - `cargo check --workspace` clean. - `make rust-test` green workspace-wide. - `make rust-lint` clean. - `./target/debug/doublezero --help` shows 29 visible top-level commands, byte-identical to the pre-refactor output. Hidden variants (`Init`, `Migrate`, `InitGeolocationConfig`, `Accounts`) remain hidden via `#[command(hide = true)]`. - `./target/debug/doublezero device --help`, `./target/debug/doublezero location --help`, and `./target/debug/doublezero multicast --help` produce the same nested verb trees. - The `location get` async ctx-consuming reference verb still works (the new dispatcher forwards `&ctx` to the relevant arm). - Targets `jo/8-cli-serviceability-command-enum`; the diff shown is only this PR's contribution. Once the chain merges to `main`, RFC-20 §Module contract item 2 is fully delivered for the serviceability module.
RFC-20 implementation stack
This PR is part of a 9-PR chain delivering RFC-20: CLI standardization. Each PR's diff is only its own contribution; reviewers should consume them in order.
doublezero-cli-corefoundation crate +solana_l1_rpc_url--solana-url+--log-verboseglobal flags + tracing initCliContextbuilt inmain+ centralized error renderingdoublezero_cli→doublezero-serviceability-clilocation getas the async +CliContextreference verbdocs/cli-standard.md+CLAUDE.mdpointerServiceabilityCommandenum + async dispatcher#[command(flatten)]+ collapse binary dispatchThis PR: #3757 — position 5 of 9. Previous: #3756 · Next: #3758
Summary of Changes
location getto the RFC-20 conforming verb pattern as the project's reference (smartcontract/cli/src/location/get.rs).GetLocationCliCommand::executeis nowasync fn, takes&CliContextas its first non-self argument, and emits atracing::debug!event so-vsurfaces what the verb is doing.doublezero_cli_core::testing::cli_context_default_for_tests()helper and exercise the new async signature via a smalltokiocurrent-thread runtime in the existing#[test]. Backend stays mocked throughMockCliCommand(auto-generated by#[automock]).client/doublezeroandcontrolplane/doublezero-adminto.awaitthe new method. Thedoublezero-adminbinary gets adoublezero-cli-coredep plus a smallCliContextbuild at startup (matching thedoublezerobinary's pattern) so the new verb is callable end-to-end.Diff Breakdown
One verb migrated end-to-end (async +
CliContext+ tracing + shared test helper); two binaries updated to.awaitthe new dispatch arm.Key files (click to expand)
smartcontract/cli/src/location/get.rs- convertsexecutetoasync fn (self, ctx, client, out), adds thetracing::debug!event, rewrites the unit test to usecli_context_default_for_tests()and a smalltokiocurrent-thread runtime around the awaited call.client/doublezero/src/main.rs- one-line change:LocationCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await.controlplane/doublezero-admin/src/main.rs- same one-line dispatch change plus aCliContextBuilder::new().with_env(...).build()?block at startup so&ctxis available.controlplane/doublezero-admin/Cargo.toml,smartcontract/cli/Cargo.toml- adddoublezero-cli-coreandtracingdeps respectively.Testing Verification
cargo test -p doublezero-serviceability-cli location::getpasses (the rewritten test exercises pubkey lookup, code lookup, and the not-found error path through the async signature).make rust-testgreen workspace-wide.make rust-lintclean.doublezero location get --helpshows the same--codeand--jsonflags as before; behavior unchanged from the user's perspective.jo/4-cli-rename-serviceability; the diff shown is only this PR's contribution.