Skip to content

feat(cli): show each wallet's currency in the picker - #64

Merged
thebrandonlucas merged 1 commit into
feat/cli-next-step-after-acceptfrom
feat/cli-picker-currency
Oct 21, 2026
Merged

thebrandonlucas merged 1 commit into
feat/cli-next-step-after-acceptfrom
feat/cli-picker-currency

Conversation

@thebrandonlucas

@thebrandonlucas thebrandonlucas commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Stack 3 of 6. Base: feat/cli-next-step-after-accept (#62). Next: fix/scripts-build-then-run.

Closes #50.

Problem

The wallet picker showed each wallet as name UUID. A USD wallet and a BTC wallet looked the same, so a user who picked a USD wallet for a BTC receive without --quote got quote_required. The guide said to pick a BTC wallet but gave no way to see which one that was.

Behavior

Wallet's balances Picker label
All report usd Payroll USD UUID
Empty, missing, not an array, a balance with no currency, or currencies that disagree Payroll UUID (as before)
  • The label is the picker's filter text, so typing btc matches wallets that show BTC (and any wallet with btc in its name). A wallet with no balance yet shows no currency; the guide and CHANGELOG say so.
  • The currency is scrubbed like the name.
  • Organization and environment choices are unchanged.
  • The picker still offers every wallet. It does not hide wallets that cannot take the payment, which is out of scope in Show the wallet currency in the wallet picker #50.

login-and-profiles.md and the changelog are updated.

Checks

On head 1f4770e:

  • cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo machete --with-metadata, cargo test --locked (109 unit, 93 integration), and python3 scripts/check-coverage.py pass. All ran in nix develop.
  • New paths have tests. A unit test covers agreeing balances, a scrubbed currency, and each case with no label. The pseudo-terminal wallet-pick test shows ops USD UUID and picks the BTC wallet by typing btc.
  • CRAP: 0 of 523 measured functions at or above 20. The highest is wait_for_payment at 19.60, unchanged from master.
  • I reviewed the diff with voltage-pr-review and the Rust style checklist.
  • Not run: a bless run, because no global flag changed.

Current-head reviewer validation

Reviewed 386c61c against feat/cli-next-step-after-accept. The head is unchanged from the completed local review.

  • Verification gate passed on this head: cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo machete --with-metadata, cargo test --locked, and python3 scripts/check-coverage.py. These reviewer checks used Rust 1.98.1 on Linux.
  • scripts/crap-report.sh --output-dir target/crap-pr-64 passed. Scope: src/, build.rs, and tests/; all targets and features. Highest score: wait_for_payment at 19.60. No functions scored 20 or higher. Measured: 523; unmeasured: 139 test functions.

@thebrandonlucas
thebrandonlucas force-pushed the feat/cli-next-step-after-accept branch from d4a558b to 72954c8 Compare October 20, 2026 18:17
@thebrandonlucas
thebrandonlucas force-pushed the feat/cli-picker-currency branch from 1f4770e to d8fdb1a Compare October 20, 2026 18:17

@thebrandonlucas thebrandonlucas left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review at d8fdb1a (Aurelius). No findings.

  • currency() returns a currency only when every balance names the same one. The unit test covers empty, mixed and missing currencies, and a non-array value.
  • The label is uppercased, then passed through scrub_line. The test checks that an ESC sequence is stripped.
  • The pseudo-terminal test shows ops USD … and picks the BTC wallet by typing btc. A UUID is hex, so btc and usd can't match one by accident.

Checks:

  • Gate on 1f4770e: fmt, clippy, machete, tests (109 unit, 93 integration) and coverage pass.
  • CRAP on 1f4770e: 0 functions at or above 20. The highest is wait_for_payment at 19.60.
  • d8fdb1a changes only CHANGELOG.md and troubleshooting.md from 1f4770e. Signed G blu@blu.cx.

@thebrandonlucas thebrandonlucas left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review of d8fdb1a, which has the same src/ and tests/ as 1f4770e. This is not an approval. I checked the backend at origin/master 1630b77c.

1. Medium: a BTC wallet that has never been funded shows no currency, and typing btc hides it. currency() (src/pick.rs:207) returns None for empty balances. In the backend, Wallet.balances is a Vec<Balance> (crates/voltage_eventing/src/wallet/entity.rs:53). The backend's own wallet classifier says that a wallet with empty balances is a never-funded BTC wallet, because USD and asset wallets always get balance entries when they are set up (crates/cli/scripts/fetch_wallet_config.sh:117-125). So a new BTC wallet, which is the likely target of the payments receive example, is listed as name UUID. login-and-profiles.md:55 then says that typing btc "lists only those", which leaves that wallet out. The CHANGELOG line at CHANGELOG.md:19 says "shows each wallet's currency", which also does not hold for those wallets.
Fix: choose one of these.

  • (a) Make the docs and CHANGELOG say what the code does: a wallet with no balance yet shows no currency, and filtering on btc leaves it out.
  • (b) Show empty balances as BTC, as the backend classifier does. Cite that rule in a comment and add a unit test.

I lean towards (a) unless the backend guarantees the rule. Also, a BTC wallet does not need a line of credit (line_of_credit_id: Option<Uuid>, entity.rs:50). So "a BTC wallet, which is on a BTC line of credit" is stronger than what the currency shows.

2. Nit: the filter matches anywhere in the label. inquire 0.9.4 is built without the fuzzy feature, so its default scorer is a case-insensitive substring match on the full label (select/mod.rs:176). A USD wallet named btc-sweep also matches btc. Fix: change "lists only those" to "lists those first", or to "matches their currency".

No other problems:

  • Organization and environment listings have no balances, so they keep name UUID.
  • The currency goes through scrub_line, and a unit test covers the escape sequence.
  • The unit test covers each None branch: empty, mixed, a missing currency, and a non-array value. The pseudo-terminal test checks the USD label and the btc filter.

Checks on d8fdb1a:

  • Gate, run in nix develop: fmt, clippy, machete, tests (109 unit, 93 integration) and coverage all pass, and the tree is clean afterwards.
  • CRAP: 0 of 523 measured functions are at or above 20. The highest is wait_for_payment at 19.60, the same as on master. nix develop has no llvm-tools-preview, so I ran CRAP with the rustup toolchain.
  • Not run: a staging check of what wallets list returns for an unfunded BTC wallet. Finding 1 comes from reading the backend source.

The wallet picker listed only a name and an ID, so a USD wallet looked
like a BTC wallet. Each wallet now shows its currency between the two
when all of its balances report the same one, and typing the currency
filters on it. A wallet with no balance currency, or with balances
that disagree, shows only its name and ID.

Closes #50
@thebrandonlucas
thebrandonlucas force-pushed the feat/cli-next-step-after-accept branch from 72954c8 to cf3f0cc Compare October 20, 2026 18:24
@thebrandonlucas
thebrandonlucas force-pushed the feat/cli-picker-currency branch from d8fdb1a to 386c61c Compare October 20, 2026 18:24

@thebrandonlucas thebrandonlucas left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-review at 386c61c (Aurelius). src/ is unchanged since my review of 1f4770e. The new login-and-profiles.md:55 text is accurate: no currency for a wallet with no balance, and the filter matches the whole label. No findings. Signed G blu@blu.cx.

@thebrandonlucas thebrandonlucas left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-review at 386c61c. This is not an approval. My medium finding and my nit are fixed, and src/ is unchanged.

  • login-and-profiles.md:55 and the CHANGELOG now say that a wallet with no balance yet shows no currency, and that btc also matches a wallet's name.
  • The line-of-credit claim is dropped.

The gate passes on 8dd04b0, which contains this commit: 109 unit and 93 integration tests, and the tree is clean.

@tee8z tee8z left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed at 386c61c. CRAP on this head: 0 of 523 functions at or above 20, highest wait_for_payment at 19.60. No blocking issues.

  • The picker reads the currency from balances[].currency, while api::wallet_currency derives it from the line-of-credit summary, and the two can disagree (an unfunded wallet, for example). Skipping a request per wallet is reasonable. A one-line comment on currency() saying it is a display hint would prevent someone from relying on it later.
  • If an asset wallet's balance currency has the asset:<hex> form, like the line-of-credit currency, the label becomes ASSET:<64 HEX>, and uppercasing changes the asset ID. Worth checking against the backend.
  • The PR description ends with a "Generated with Claude Code" line; AGENTS.md says to leave tool attribution out of PR descriptions.

The inline suggestions remove a Some(match …) by letting with_currency take the Option. I applied the suggestions on this head and checked them: cargo clippy --all-targets -- -D warnings is clean and the unit and integration tests pass.

Comment thread src/pick.rs
Comment on lines +195 to +199
let choice = Choice::new(id, name);
Some(match currency(item) {
Some(currency) => choice.with_currency(currency),
None => choice,
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With with_currency taking an Option (see terminal.rs), the match goes away:

Suggested change
let choice = Choice::new(id, name);
Some(match currency(item) {
Some(currency) => choice.with_currency(currency),
None => choice,
})
Some(Choice::new(id, name).with_currency(currency(item)))

Comment thread src/terminal.rs
Comment on lines +140 to +141
pub fn with_currency(mut self, currency: &str) -> Self {
self.currency = Some(scrub_line(&currency.to_uppercase()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Taking the Option here lets choices chain it:

Suggested change
pub fn with_currency(mut self, currency: &str) -> Self {
self.currency = Some(scrub_line(&currency.to_uppercase()));
pub fn with_currency(mut self, currency: Option<&str>) -> Self {
self.currency = currency.map(|currency| scrub_line(&currency.to_uppercase()));

@tee8z tee8z left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved 386c61c against feat/cli-next-step-after-accept. The picker preserves unknown or mixed currency behavior and scrubs displayed text. Remaining simplification suggestions are nonblocking. This approves the layer against #62; that base still has requested changes.

Validation on this unchanged head: cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo machete --with-metadata, cargo test --locked, and python3 scripts/check-coverage.py passed. CRAP: 523 measured functions, none at or above 20; highest wait_for_payment 19.60. 139 test functions were unmeasured.

@thebrandonlucas
thebrandonlucas merged commit a6c93b6 into feat/cli-next-step-after-accept Oct 21, 2026
8 of 14 checks passed
@thebrandonlucas
thebrandonlucas deleted the feat/cli-picker-currency branch October 21, 2026 13:42
thebrandonlucas added a commit that referenced this pull request Oct 21, 2026
The wallet picker listed only a name and an ID, so a USD wallet looked
like a BTC wallet. Each wallet now shows its currency between the two
when all of its balances report the same one, and typing the currency
filters on it. A wallet with no balance currency, or with balances
that disagree, shows only its name and ID.

Closes #50
thebrandonlucas added a commit that referenced this pull request Oct 21, 2026
* feat(cli): name the next step after an accepted receive or quote

An accepted payments receive or quotes create returns no body, so
human output now names the command that shows the invoice, address,
or quote, with the --org, --env, and --account that the command used.
--quiet and machine-readable output leave the hint out, and so does a
request body without an ID.

A command that takes a resource ID also takes it as --id, as
quotes create and payments send do, and rejects both at once.

Closes #52
Closes #36

* feat(cli): show each wallet's currency in the picker (#64)

The wallet picker listed only a name and an ID, so a USD wallet looked
like a BTC wallet. Each wallet now shows its currency between the two
when all of its balances report the same one, and typing the currency
filters on it. A wallet with no balance currency, or with balances
that disagree, shows only its name and ID.

Closes #50

* fix(scripts): build, then run the command after a leading --build (#65)

* feat(cli): show each wallet's currency in the picker

The wallet picker listed only a name and an ID, so a USD wallet looked
like a BTC wallet. Each wallet now shows its currency between the two
when all of its balances report the same one, and typing the currency
filters on it. A wallet with no balance currency, or with balances
that disagree, shows only its name and ID.

Closes #50

* fix(scripts): build, then run the command after a leading --build

`scripts/voltage-staging --build login ...` passed `--build` to the
binary, which rejected it. A leading `--build` in either wrapper now
builds and then runs the remaining arguments, if any. The wrapper still
refuses `--config-dir`, `--api-url` and `--auth-url` before it builds,
and a failed build exits with cargo's status without running the command.

Closes #37.
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.

2 participants