[codex] add Ark receive and transfer status CLI - #451
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces new CLI commands and RPC endpoints for listing Ark receive targets and transfer statuses. Key additions include the receive list and transfers list commands, supported by server-side logic that aggregates transfer data from rounds, OOR sessions, and transaction history. Feedback identifies several critical issues: the collectTransfers method uses a hardcoded limit that breaks pagination for large histories, and an integer conversion of the offset could cause panics on 32-bit systems. Additionally, it is recommended to use the command context for RPC calls to ensure proper cancellation, and to improve the uniqueness of the TransferId for temporary rounds to avoid collisions.
| pending, err := r.pendingRoundTransfers(ctx) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| transfers = append(transfers, pending...) | ||
|
|
||
| history, err := r.historyTransfers( | ||
| ctx, "round", | ||
| daemonrpc.TransferMode_TRANSFER_MODE_INROUND, | ||
| ) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| transfers = append(transfers, history...) | ||
| } | ||
|
|
||
| if transferModeAllowed(req, daemonrpc.TransferMode_TRANSFER_MODE_OOR) { | ||
| oorTransfers, err := r.oorTransfers(ctx) |
There was a problem hiding this comment.
The collectTransfers method uses a hardcoded limit of maxListTransfersLimit (1000) when fetching from underlying sources (ListRounds, ListTransactions). This effectively caps the total number of transfers that can be listed and searched, regardless of the offset provided in the ListTransfersRequest. If a user has more than 1000 history entries, older entries will be unreachable via this RPC. Additionally, filtering happens in-memory after this truncation, which may lead to incomplete results if matching entries exist beyond the first 1000. Consider fetching a larger window or implementing a more robust pagination strategy that accounts for the requested offset and limit across all sources.
There was a problem hiding this comment.
Fixed and folded into 1ef001da. historyTransfers now walks ListTransactions source pages until exhaustion, and pendingRoundTransfers walks ListRounds cursor pages instead of truncating at the first page.
| start := int(req.GetOffset()) | ||
| if start > len(transfers) { | ||
| start = len(transfers) | ||
| } |
There was a problem hiding this comment.
On 32-bit systems, converting a uint32 offset to int can overflow if the offset is greater than math.MaxInt32. This would result in a negative start value, causing a panic when slicing the transfers array. It is safer to compare the uint32 offset with the length of the slice before conversion.
| start := int(req.GetOffset()) | |
| if start > len(transfers) { | |
| start = len(transfers) | |
| } | |
| offset := req.GetOffset() | |
| if offset > uint32(len(transfers)) { | |
| offset = uint32(len(transfers)) | |
| } | |
| start := int(offset) |
There was a problem hiding this comment.
Fixed and folded into 1ef001da. ListTransfers now converts the uint32 cursor through clampedTransferStart, which compares using uint64 before converting to int.
| return err | ||
| } | ||
|
|
||
| resp, err := client.ListReceiveScripts(context.Background(), req) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed and folded into 1ef001da. The new receive-list RPC call now uses cmd.Context() so CLI cancellation propagates.
| return err | ||
| } | ||
|
|
||
| resp, err := client.ListTransfers(context.Background(), req) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed and folded into 1ef001da. The transfer-list RPC call now uses cmd.Context() so CLI cancellation propagates.
| id = fmt.Sprintf("temp:%t:%s", round.GetIsTemp(), | ||
| round.GetState().String()) |
There was a problem hiding this comment.
The generated TransferId for temporary rounds (where round_id is empty) is not guaranteed to be unique if multiple rounds are in the same state. This can lead to collisions in the TransferId field, which is intended to be a stable local identifier. Consider incorporating a more unique property, such as a local sequence number or the creation timestamp, to ensure uniqueness.
There was a problem hiding this comment.
Fixed and folded into 1ef001da. Temporary round rows now use temporaryRoundTransferID, which includes round state, timestamps, tx/outpoint context, and a per-list index to avoid collisions before a server round id exists.
Code ReviewPR: [codex] add Ark receive and transfer status CLI OverviewThis PR adds two new daemon RPCs ( Bugs / Correctness1.
// darepod/rpc_transfers.go – ListTransfers
func (r *RPCServer) ListTransfers(ctx context.Context, ...) {
// missing: if err := r.requireWalletReady(); err != nil { return nil, err }2. Silent data truncation before pagination
3. In direction := daemonrpc.TransferDirection_TRANSFER_DIRECTION_UNSPECIFIEDThis means a request with Design / Maintainability4. // cmd/darepocli/darepoclicommands/cmd_receive.go
cmd := &cobra.Command{
RunE: oorReceive, // borrows OOR implementation
}
cmd.Flags().String("label", "", "...")
5. Unusual targets := make(
[]*daemonrpc.ReceiveTarget, 0,
len(
resp.GetScripts(),
),
)
Minor Nits6. Missing
7. UpdatedAtUnixS: tx.GetCreatedAtUnixS(), // no separate update time availableThe intent is clear but a short comment would make the duplication intentional, not a copy-paste oversight. 8.
What Looks Good
SummaryThe blocking items are (1) the missing |
5781f33 to
1ef001d
Compare
Code ReviewOverviewThis PR adds a user-friendly Bugs / Correctness1. // current code
UpdatedAtUnixS: tx.GetCreatedAtUnixS(),This field is intentionally set to the creation time (likely because history rows have no separate update time), but it means callers who inspect 2.
3. In-round pending transfers always show
Performance Concern
The safe path for an initial landing is to cap the source fetches — e.g., only fetch Style / Minor Issues4. Unusual // current
targets := make(
[]*daemonrpc.ReceiveTarget, 0,
len(
resp.GetScripts(),
),
)
targets := make(
[]*daemonrpc.ReceiveTarget, 0, len(resp.GetScripts()),
)5. Redundant mode filtering in
6. history, err := r.historyTransfers(ctx, "round", ...)If Test CoverageThe tests are well-structured and cover the key utility functions. A few gaps worth noting:
SummaryThe CLI and proto design is solid, and the utility functions ( |
1ef001d to
e17d5f0
Compare
|
Addressed the first Claude review in
Re-running Claude via the existing |
Code ReviewOverviewThis PR adds three user-facing features that make the Ark CLI usable without requiring knowledge of protocol internals:
The approach of stitching three backend sources (pending round FSM states, committed transaction history, OOR sessions) into one response is well-motivated and the shape of the API is clean. Generated code ( CorrectnessRound deduplication across sources
Direction inference is fragile
if strings.Contains(subtype, "received") ||
tx.GetCreditAccount() == "transfers_in" {If subtype strings are ever renamed or localized, direction silently falls back to
PerformanceAll data is loaded before pagination
StyleOver-wrapped // current
targets := make(
[]*daemonrpc.ReceiveTarget, 0,
len(
resp.GetScripts(),
),
)The inner // suggested
targets := make(
[]*daemonrpc.ReceiveTarget, 0, len(resp.GetScripts()),
)Empty validation closure in if err := parseRequest(cmd, req, func() error {
return nil
}); err != nil {If
key := pkScript[taprootPkScriptKeyOffset:]The length check above guarantees exactly 34 bytes, so this always yields 32 bytes. An explicit end bound makes the intent self-documenting with no runtime cost: key := pkScript[taprootPkScriptKeyOffset:taprootPkScriptLen]TestsUnit coverage of the helper functions is solid: direction/status converters, pagination helpers, What's missing:
Minor Notes
|
e17d5f0 to
5b45e3b
Compare
|
Folded the second Claude pass into
Local gate is green again after regenerating protobuf stubs. |
Code Review: [codex] add Ark receive and transfer status CLIOverall this is a well-scoped PR that delivers the stated UX goal clearly. The abstractions are clean, tests are present and parallel, and the Correctness / Logic
The loop initialises // rpc_transfers.go – persisted flips mid-cursor, may skip live rounds
persisted = true // set after first page; round-index also increments on skip
This is fine, but Style / ConventionsExcessive targets := make(
[]*daemonrpc.ReceiveTarget, 0,
len(
resp.GetScripts(),
),
)
No-op if err := parseRequest(cmd, req, func() error {
return nil
}); err != nil {
return err
}
Missing PerformanceIn-memory aggregation for
Minor Observations
What's Good
|
5b45e3b to
d600f19
Compare
|
Folded the remaining third-pass clarity nits into
Local full gate is green again: |
|
Code Review Overview This PR adds a user-facing receive and transfers list CLI surface over two new daemon RPCs (ListReceiveScripts, ListTransfers), plus an address field in NewReceiveScriptResponse. The overall design is clean and the code is well-tested. A few issues worth addressing before merge. Issues 1. Bug: persisted flag changes mid-pagination in pendingRoundTransfers In darepod/rpc_transfers.go the persisted variable starts false and flips to true after the first page. If ListRounds uses that flag to switch data sources independently of the page token, the second and later pages return a different dataset and rounds can be silently skipped. Either keep persisted constant throughout (relying on the page token to continue), or split the loop into two sequential walks: one for live rounds (PersistedOnly: false, single pass) and one for persisted rounds (PersistedOnly: true, paginated). 2. In-memory unbounded collection before pagination collectTransfers exhausts every matching source store into memory before slicing for pagination. For a wallet with a long history, --limit 5 --offset 0 still forces a full scan of all stores. The in-code comment acknowledges this is a V1 tradeoff, which is fine, but a TODO would prevent it silently becoming a production performance problem as history grows. 3. Double-counting race window The comment in collectTransfers notes: A round that completes between reads can briefly appear once as a pending round row and once as a committed history row. The transfer IDs differ (round: from the pending path vs round::<entry_id> from the history path), so they will not be deduplicated. A user running transfers list at exactly the wrong moment sees the same transfer twice with conflicting statuses. Is this an accepted known limitation, or should deduplication by round_id be applied before returning? 4. Style: awkward make formatting in ListReceiveScripts In darepod/rpc_receive_targets.go the capacity argument to make is wrapped on its own line with len() on its own line inside. Project style puts simple expressions inline: Minor Notes
Positives
|
d600f19 to
5d6926e
Compare
|
Folded the fourth Claude pass into
Full local gate is green again, including regenerated protobuf stubs. |
Code ReviewOverviewThis PR adds user-facing Positives
Issues1. Potential duplicate rows under concurrent in-round round transitions (
|
5d6926e to
996974a
Compare
|
Folded the fifth Claude pass into
Full local gate is green again after regenerating stubs. |
Code ReviewOverviewThis PR adds Strengths
IssuesMedium –
|
996974a to
9d89047
Compare
|
Folded the latest review pass into 9d89047. This adds transaction-history status mapping instead of hard-coding completed, covers failed status/subtype mapping in tests, parallelizes the table subtests, documents the OP_DATA_32 taproot-script offset, and explains the dedupe tie-break. I also expanded the PR body with concrete CLI examples, the full-scan limitation, and the rows that can currently report unknown direction or zero amount.\n\nLocal validation on the amended head: |
Code ReviewOverall this is a well-structured PR. The intent is clear, the commit messages look tidy, and the core logic is easy to follow. Observations below, roughly in priority order. Issues1.
subtype := strings.ToLower(tx.GetSubtype())
if strings.Contains(subtype, "failed") || status == "failed" {
2. // collectTransfers gathers transfers from the existing operation-status and
// transaction-history stores before common filtering and pagination.Filtering happens inside 3.
return nil, status.Errorf(codes.Internal, "unable to list "+
"receive scripts: %v", err)
4. The test covers an empty request (pass), fully-specified match (pass), and direction mismatch (fail). Missing:
5. Direction-filter interaction with
Minor / Style6. Redundant hasMore := end < len(transfers)
// ...
if hasMore {
resp.NextOffset = nextTransferOffset(req.GetOffset(), limit)
}
7.
// TODO: add pagination if receive-script registrations become
// long-lived enough for this list to grow without bound.TODOs are fine, but they tend to rot. If there is an issue tracker entry for this, reference it. If not, it is worth opening one so it does not disappear. 8. Inline
return "round:" + roundID + fmt.Sprintf(":%d", tx.GetEntryId())This mixes two concatenation styles. A single Positive Notes
|
9d89047 to
c01ed49
Compare
|
Folded the latest Claude round into c01ed49c0. Changes in this pass:\n\n- replaced fuzzy |
Code Review — PR #451: Add Ark receive and transfer status CLIOverviewThis PR adds Bug Fix (Nice Catch)
IssuesDirection filter silently passes unknown-direction rows
if direction == daemonrpc.TransferDirection_TRANSFER_DIRECTION_UNSPECIFIED {
// Live in-round rows can be useful even before the local
// input/output hints needed for direction classification exist.
return true
}A user running
|
c01ed49 to
2727a75
Compare
|
Folded the latest Claude round into 2727a75. This pass adds the direction-filter contract directly to the proto docs and regenerates the daemon RPC stubs, so the |
Code ReviewOverviewThis PR adds three user-facing improvements: a Positives
IssuesSemantics / Correctness1. if direction == daemonrpc.TransferDirection_TRANSFER_DIRECTION_UNSPECIFIED {
return true // passes outgoing, incoming, or any filter
}The intent (show live in-round rows even when direction is unknown) is documented in the PR description but not in the CLI
This wording is in 2. case len(round.GetInputOutpoints()) > 0:
return TRANSFER_DIRECTION_OUTGOING
case len(round.GetOutputOutpoints()) > 0:
return TRANSFER_DIRECTION_INCOMINGA round where both inputs and outputs are locally known (both sent and received VTXOs visible) would be classified as "outgoing" because 3. The function signature accepts a Performance / Scalability4. Full in-memory scan in The code has a clear TODO comment, but the scale ceiling is worth calling out explicitly: 5.
Minor / Style6. if req == nil {
req = &daemonrpc.ListTransfersRequest{}
}gRPC handlers receive a decoded request from the framework; it will never be nil. The guard can be removed. 7. The pre-Go-1.22 loop variable capture idiom ( 8.
9. The function builds an intentionally fragile id from live state. A comment explaining that these ids are not stable across restarts (the point being that they only need to be unique within a single response) would help reviewers distinguish this from the stable SummaryThe implementation is correct and the known scalability limitations are clearly documented. The main actionable items are:
The deduplication logic, overflow guards, and context propagation fixes are all correct. The proto changes are backward compatible and follow existing patterns. |
2727a75 to
6530193
Compare
|
Folded the latest hardening suggestions into This pass keeps temporary live-round ids bounded by hashing the variable round fields and including only I also expanded the persisted pending-round scan comment to cover the live-plus-persisted pending duplicate case, sharpened the Local validation on this head: |
Code ReviewOverviewThis PR adds three user-facing CLI commands ( What's Good
Issues and Suggestions1. Direction filter silently passes UNSPECIFIED rows (medium)
2. No dedup across OOR sources (low, future risk)
3. The inner pagination loop over 4.
5. Clamped The clamped 6. Proto:
Minor Style Notes
SummaryThe overall approach is sound and the documented trade-offs are honest. The most actionable items are #1 (direction-filter UX surprise — the behaviour is correct but the help text undersells it) and #3 (unbounded round page scans — worth tracking as a follow-up). Everything else is low-risk. The test suite is well-structured and covers the key conversion and edge-case logic. |
e9a6bed to
4a1ae46
Compare
|
Folded the latest Claude pass into This round makes the Local validation on this head: |
Code Review — PR #451: Add Ark receive and transfer status CLIOverviewThis PR introduces three user-facing CLI surfaces ( Issues Worth Addressing1.
2. Lexicographic comparison of numeric entry-ID suffixes is fragile In return candidate.GetTransferId() > current.GetTransferId()History-row IDs are built as // Compare by numeric entry id to avoid lexicographic ordering surprises
// when id crosses a decade boundary.
return candidate.GetEntryId() > current.GetEntryId()3. Magic-string coupling in // rpc_transfers.go
transactionHistoryStatusFailed = "failed"This string has to match whatever Minor Observations4. The inner pagination loop fetches all persisted round pages filtering for non-terminal rounds. The TODO is present and the reasoning is sound for current wallet sizes, but consider noting the worst-case latency with very large histories in the docstring, so future maintainers know what to expect before that store-level cursor lands. 5. Correctness nit in for offset := uint32(0); ; {
// ...
nextOffset := resp.GetNextOffset()
if nextOffset <= offset || nextOffset > maxTransferSourceOffset {
break
}
offset = nextOffset
}On the first iteration 6. parts := []string{
fmt.Sprintf("is_temp:%v", round.GetIsTemp()), // hashed
...
}
return fmt.Sprintf("is_temp:%v:%x:index:%d", round.GetIsTemp(), ...) // also in output
What's Done Well
SummaryItems 1 and 2 are the ones worth double-checking before merge. Item 1 could result in the 🤖 Reviewed with Claude Code |
4a1ae46 to
ea11364
Compare
|
Folded the latest Claude findings into This pass makes the I also documented that the failed transaction-history status string mirrors Local validation on this head: |
Code ReviewOverviewThis PR adds three user-facing CLI surfaces — Correctness
filtered := transfers[:0]
for _, transfer := range transfers {
if transferMatchesFilters(transfer, req) {
filtered = append(filtered, transfer)
}
}This relies on the invariant that the write index never overtakes the read index in a filter-in-place loop. That invariant holds here, but the subsequent call to
_, suffix, ok := strings.Cut(strings.TrimPrefix(id, "round:"), ":")For an OOR history-backed ID like
The inner loop pages through every persisted round row to find pending ones: for {
roundResp, err := r.ListRounds(ctx, &daemonrpc.ListRoundsRequest{
PageSize: int32(maxListTransfersLimit),
...
})
...
}
func transferDirectionMatchesFilter(direction, filter daemonrpc.TransferDirection) bool {
if direction == daemonrpc.TransferDirection_TRANSFER_DIRECTION_UNSPECIFIED {
return true
}
return direction == filter
}This is intentional and documented in both the proto and the CLI Style / Consistency
maxTransferSourceOffset uint32 = 1<<31 - 1The comment says it "mirrors the signed SQL offset bound" — using Test CoverageThe unit-test coverage for pure conversion and filter helpers is solid. A few gaps worth noting:
Proto / API DesignThe shape is clean and consistent with existing responses (
SummaryThe code is well-factored, thoroughly commented, and handles edge cases (overflow, nil inputs, unknown enum values) defensively. The main items worth addressing before merge:
|
ea11364 to
cef870a
Compare
|
Folded the latest Claude cleanup pass into This pass removes the in-place transfer filter aliasing by building a fresh filtered slice, narrows I also added a success-path test for Local validation on this head: |
Code ReviewOverviewThis PR adds three user-facing CLI commands ( Positives
IssuesPerformance:
|
cef870a to
9388507
Compare
|
Folded the latest Claude review into This pass addresses the new review items directly: I also added targeted tests for the transfer dedupe/supersession path and expanded the newest-first sort test so it covers the zero- Local validation on this head: Claude, please re-review this latest head. |
Code ReviewOverviewThis PR adds Positives
IssuesMedium1. O(full history) scan on every
for {
roundResp, err := r.ListRounds(ctx, &daemonrpc.ListRoundsRequest{
PageSize: int32(maxListTransfersLimit),
PageToken: nextToken,
PersistedOnly: true,
})
// ... iterates until nextToken == ""
}Similarly, The TODO ( 2. No The individual helper functions are well-tested, but the full handler paths — including Low3. Schema test misses
4. The subtype field takes priority over credit/debit account. There is no test for a row where 5. Unknown-direction pass-through may need more prominent CLI help text The Nits
SummaryThe design is sound and the PR is well-scoped. The two medium issues are pre-acknowledged scalability tradeoffs that are acceptable for local-wallet CLI use — they just deserve a follow-up ticket if this RPC is ever exposed in production tooling. The unit test gap on the RPC handlers is the most actionable item before merge. |
9388507 to
2457386
Compare
|
Folded one more Claude follow-up pass into This pass adds handler-level readiness tests for both new RPCs, expands the transfer direction test with the subtype-vs-account priority case, verifies the schema registry keeps I left the full-history scan as the documented local-wallet tradeoff for this PR; the code already skips the pending-round scan for terminal status filters and the remaining O(total history) behavior is called out in the implementation comments for a future source-level pagination/filter pushdown. Local validation on this head: Claude, please re-review this latest head. |
Code Review: PR #451 — Add Ark receive and transfer status CLISummary: Adds Code Quality & Style
Potential Bugs & Correctness
Performance
SecurityNo direct security issues. Two minor points to verify on the daemon side:
Test CoverageWhat's covered well:
Gaps:
API Design
Summary
The core logic is correct, context propagation is fixed, tests cover the new enum paths and schema registry, and the protobuf changes are backwards compatible. The items above are all minor — approve after addressing the schema description nits and confirming the daemon-side TODO is tracked. Reviewed by Claude (claude-sonnet-4-6) |
2457386 to
ea997fd
Compare
|
Folded the final Claude polish pass into This pass expands the transfer schema descriptions so tool callers can see the valid enum values directly, updates the transfer-list Local validation on this head: Claude, please re-review this latest head. |
Code Review — PR #451: Add Ark receive and transfer status CLIOverviewThis PR adds three user-facing CLI commands ( Overall this is well-structured, well-documented, and well-tested. The design choices are justified in comments and the PR description. A few items are worth addressing before merge. Issues1.
|
Users need a receive command that works for quick local Ark tests. The old CLI exposed lower-level pieces, so basic receive flows were hard to discover without reading code. This adds generic receive commands plus a transfer list that reports in-round and OOR sends and receives through one status surface. The daemon also returns the bech32m address for new receive scripts, so callers do not need to derive it themselves. Transfer listing now walks paginated source history before filtering, so older matching rows are not hidden behind the first source page. The CLI uses command contexts for new RPCs, and temporary round ids now avoid collisions when live rounds have no server id yet.
ea997fd to
5e6c0be
Compare
|
Folded the latest Claude review into This pass skips committed round-history scans for pending-only transfer requests, replaces the raw Local validation on this head: @claude, please re-review this latest head. |
|
@claude re-review |
|
Claude finished @bhandras's task in 2m 27s —— View job Code Review
This PR has been through an extensive review cycle and the resulting code is in very good shape. The main concerns from previous rounds have all been addressed. Here is what the current head looks like. What Looks Good
Minor Remaining Observations1. Not introduced by this PR, but now that 2. OOR transfers fetched unconditionally under
3. Schema description vs. CLI flag behavior for The schema describes 4.
SummaryAfter this many review iterations, the code is clean, well-commented, and well-tested. None of the above observations are blockers. The pre-existing |
Summary
This PR makes the Ark CLI receive/status story usable without forcing users to know which lower-level protocol path they are exercising or to inspect daemon internals.
Today the CLI can create a boarding address, but there is no friendly generic receive command and no single place to inspect in-round/OOR transfer activity. That makes quick local testing awkward: users can generate a receive script, but then have to infer what happened by stitching together other command output.
This adds:
darepo receiveas the friendly default receive target command.darepo receive listto show locally known reusable receive/boarding targets.darepo transfers listto show in-round and OOR sends/receives with status.ListReceiveScriptsandListTransfers.NewReceiveScriptResponse, so callers no longer need to derive it from the returned script.User-Facing Examples
Create a generic Ark receive target:
The command uses the same receive-script machinery as OOR receive target creation, but exposes it under the simpler command name users expect when they just want an address to hand out.
Create the same kind of receive target through the existing OOR namespace:
Both commands return the pkScript plus the derived bech32m address. Existing scripts that call
oor receivekeep working, while new local-testing flows can usereceivedirectly.List receive targets this wallet/daemon knows about:
This is useful after a test session where multiple boarding/receive addresses were generated and you want to recover the exact script/address pairs without digging through logs.
List all transfer activity:
List only pending in-round activity:
List only completed OOR receives:
Page through a larger history:
The transfer rows include stable identifiers, mode, direction, status, amount, timestamps where available, and context such as txid/round ID/error text depending on the source record.
API Changes
NewReceiveScriptResponsenow includesaddress, derived from the taproot pkScript and the active network parameters.ListReceiveScriptsreturns the local receive targets indexed by the daemon.ListTransfersreturns a normalized view over:The transfer list intentionally normalizes these sources into one response so CLI callers do not need separate commands for “in-round send”, “in-round receive”, “OOR send”, and “OOR receive” just to answer “what happened?”
Current Limitations
ListTransfersaggregates several existing status/history sources in memory and then applies the publiclimit/offsetpage. That is expected to be fine for the small local-wallet histories this CLI is aimed at today, but it is not yet a database-level merged cursor for very large archival wallets. The code carries a TODO to replace the full scan with source-aware cursors if transfer history grows enough to need that.Some rows can only expose the data available from their source. Live in-round rows may have unknown direction until local input/output hints or persisted ledger rows exist. Direction filters keep those unknown live rows visible rather than hiding pending activity behind
--direction incomingor--direction outgoing. OOR receive/session rows can also reportamount_sat = 0when the local status source does not yet know the final amount. The CLI still shows these rows so users can track lifecycle status instead of losing pending activity entirely.Schema Registry
The method registry now includes schemas for:
receivereceive.listtransfers.listIt also refreshes the stale
send.oorschema so it advertises the actual destination inputs: exactly one oftoorpubkey. The removedpk_scriptschema entry was not accepted by the command parser, so this is a registry correction rather than a daemon/API removal.Validation
go test ./...make fmt-changedmake fmt-changed-checkmake lint-nativemake commitmsg-lint range="origin/main..HEAD"make schema-checkmake doc-check(passes; reports pre-existing CLAUDE.md/AGENTS.md divergence warnings inbaselib/actoranddb/actordelivery/migrations)git diff --check