From 941fdf42b6d8b32d7e767a8b39f96fcedd20ec4e Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Sat, 1 Aug 2026 08:01:31 -0400 Subject: [PATCH 01/22] docs(ffi): error-code registry for the FFI result space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four open PRs allocate discriminants into PlatformWalletFFIResultCode in parallel, with no shared source of truth. A duplicate discriminant does not produce a textual merge conflict, so the second merge silently misclassifies errors on every host — one such collision (code 29) has already required a renumber directive in review. Adds packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md: the merged allocation table (0-26, 98, 99), the proposed allocations with owning PRs (27-33), the rule for claiming the next free integer, the ABI-stability rule (never renumber after release, deprecate instead), and the currently contested allocations. Links it from the crate README's error-handling section. Docs only — no enum, mapping, or mirror is changed. Renumbering remains the owning PRs' work. Co-Authored-By: Claude Opus 4.8 --- .../ERROR_CODE_REGISTRY.md | 157 ++++++++++++++++++ packages/rs-platform-wallet-ffi/README.md | 6 + 2 files changed, 163 insertions(+) create mode 100644 packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md new file mode 100644 index 00000000000..3d1c883b189 --- /dev/null +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -0,0 +1,157 @@ +# FFI Error-Code Registry + +Single source of truth for the integer values of +`PlatformWalletFFIResultCode` (`packages/rs-platform-wallet-ffi/src/error.rs`). + +Every value in that enum is **public ABI**. `cbindgen` emits it into the +generated C header, and hosts compare against the integer — Swift +(`packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletResult.swift`) +mirrors it as a `RawRepresentable` enum, Kotlin +(`packages/kotlin-sdk/.../errors/DashSdkError.kt`) branches on it in +`fromPlatformWalletNative`. A shipped host binary that was compiled against +one numbering keeps using that numbering. + +This file exists because several feature branches allocate into the same +integer range in parallel. A duplicate discriminant in two branches does **not** +produce a textual merge conflict — the second merge silently misclassifies +errors on every host — so allocations have to be reconciled here, in one place, +rather than in each branch's diff. + +## Rules + +1. **Claim the next free integer** from the table below — the first value not + listed as merged, proposed, or reserved. Do not reuse a gap unless this file + marks it free. +2. **Record the claim in this file in the same PR** that adds the variant. A PR + that adds a code without a row here is incomplete. +3. **Never renumber a code after it has shipped in a release.** Deprecate + instead: leave the row, mark it deprecated, and allocate a new integer. Codes + that are still only proposed (unmerged) may be renumbered to resolve a + collision; codes on `v4.2-dev` may not. +4. **Do not reuse a retired integer.** Mark it reserved and move on. +5. **Update the mirrors in the same PR**: the Rust enum, the Swift + `PlatformWalletResultCode` + its `init(result:)` switch, and — where the code + deserves typed handling — the Kotlin `fromPlatformWalletNative` mapping and + `DashSdkErrorTest`. Kotlin is allowed to be non-exhaustive: unmapped codes + fall through to `PlatformWallet.Generic(code, …)`, which preserves the + integer. Swift is exhaustive; an unmirrored code surfaces as + `.errorUnknown` there and loses its identity. +6. **Blocks 98–99 are terminal sentinels** (`NotFound`, `ErrorUnknown`) and are + not an allocation frontier. New codes go after the highest allocated value + below them. + +## Merged allocations (`v4.2-dev`) + +These are shipped ABI. Do not renumber. + +| Code | Name | Notes | +| ---: | --- | --- | +| 0 | `Success` | | +| 1 | `ErrorInvalidHandle` | | +| 2 | `ErrorInvalidParameter` | | +| 3 | `ErrorNullPointer` | | +| 4 | `ErrorSerialization` | | +| 5 | `ErrorDeserialization` | | +| 6 | `ErrorWalletOperation` | | +| 7 | `ErrorIdentityNotFound` | | +| 8 | `ErrorContactNotFound` | | +| 9 | `ErrorInvalidNetwork` | | +| 10 | `ErrorInvalidIdentifier` | | +| 11 | `ErrorMemoryAllocation` | | +| 12 | `ErrorUtf8Conversion` | | +| 13 | `ErrorArithmeticOverflow` | Reserved slot — declared, no in-tree producer; holds the number for the mapping arriving via #3549 | +| 14 | `ErrorNoSelectableInputs` | | +| 15 | `ErrorWalletAlreadyExists` | | +| 16 | `ErrorShieldedBroadcastFailed` | | +| 17 | `ErrorShieldedBroadcastUnconfirmed` | | +| 18 | `ErrorShieldedSpendUnconfirmed` | | +| 19 | `ErrorShieldedNoRecordedAnchor` | | +| 20 | `ErrorTransactionBroadcastUnconfirmed` | | +| 21 | `ErrorAddressNonceMismatch` | | +| 22 | `ErrorCoreInsufficientFunds` | | +| 23 | `ErrorAssetLockNotTracked` | | +| 24 | `ErrorAssetLockAlreadyConsumed` | | +| 25 | `ErrorAssetLockFundingMismatch` | | +| 26 | `ErrorTransactionBroadcastRejected` | Merged in `9302c62e8b`; took a number several open branches had been treating as free | +| 98 | `NotFound` | Sentinel — `Option` returned as an error | +| 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | + +**Next free integer: 34** (see the proposed table; 27–33 are claimed). + +## Proposed allocations (open PRs) + +Not yet ABI. Numbers here may still move; they move by agreement recorded in +this file. + +| Code | Name | Owning PR | Status | +| ---: | --- | --- | --- | +| 27 | `ErrorStaleReservationToken` | #4185 | In review (also carried by #4256) | +| 28 | `ErrorReservationTokenConsumed` | #4185 | In review (also carried by #4256) | +| 29 | `ErrorReservationWalletMismatch` | #4185 | **Collision** — see below | +| 29 | `ErrorAssetLockInsufficientFunds` | #4184 | **Collision** — see below | +| 30 | — | — | **Unallocated.** Reserved in sibling comments only; see below | +| 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204) | +| 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | +| 33 | `ErrorTransactionSigning` | #4256 | In review | + +Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code: #4186, +#4191, #4194, #4195, #4240, #4251, #4258. + +## Contested and pending + +### 29 — `ErrorReservationWalletMismatch` (#4185) vs `ErrorAssetLockInsufficientFunds` (#4184) + +Both PR heads define code 29. This is the known collision: review on #4185 +directed that PR to keep #4184's `29 = ErrorAssetLockInsufficientFunds` and move +`ErrorReservationWalletMismatch` to 30. That renumber has not landed on #4185's +head, and #4256 (stacked downstream) carries the pre-renumber `29`. + +Resolution of record: **#4184 keeps 29; #4185 moves to 30**, propagated through +the Rust enum, the FFI `From` mapping, Swift `PlatformWalletResult`, Kotlin +`DashSdkError` (+ `DashSdkErrorTest`), and the JNI rustdoc — plus #4256, which +inherits the value. + +### 30 — reserved in comments for a variant that no longer exists + +`ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in +in-tree comments on #4183, #4204, and #4247/#4256's numbering rationale. It is +**not defined anywhere** — #4184, the PR that would have introduced it, does not +contain it after a re-scope. 30 is therefore free, and is the slot the #4185 +renumber above should take. The stale "reserved for the consent code" comments +should be dropped by whichever PR touches them next. + +### 26 — `ErrorStaleReservationToken` on #4196 collides with merged ABI + +#4196 (stacked on #4185) branched before `26 = ErrorTransactionBroadcastRejected` +merged, and its head numbers the reservation trio **26 / 27 / 28**. Merging it as +it stands would give 26 two meanings and would contradict #4185's own 27 / 28 / 29 +for the same three names. #4196 needs a rebase onto current `v4.2-dev` and must +adopt whatever numbering #4185 lands with. No new integers are needed for it. + +### 31 vs 33 — two signing-related codes, deliberately distinct + +Review on #4256 suggested mapping its signing failure onto 31. #4256 declined and +took 33, on the grounds that 31 (`ErrorSigningKeyUnavailable`, #4183) asserts a +specific contract — the signer holds no usable private key for a requested public +key, restored from a typed signer completion code — whereas #4256's +`BuilderError::SigningFailed` also covers unresolved derivation paths, sighash +failures, and malformed signature encodings. Both codes are currently allocated. +Maintainers may still choose to collapse them; that decision belongs to #4183 and +#4256 jointly and should be recorded here. + +## Sibling FFI crates + +`rs-sdk-ffi`'s `DashSDKErrorCode` (`packages/rs-sdk-ffi/src/error.rs`) is a +**separate** integer space (0–10, plus `InternalError = 99`) and is not contested +by any of the PRs above — none of them modify it. Do not assume a number means +the same thing in both enums. + +## Survey provenance + +Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c` and the following PR +heads: #4183 `2cd948331b`, #4184 `a9e418af50`, #4185 `7d85953c2a`, #4186 +`6f7abbadc1`, #4191 `8acb0bd14c`, #4194 `9efc0b7e3a`, #4195 `4f2eb06d64`, #4196 +`ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `72c000dcfd`, #4251 +`176f8ed3eb`, #4256 `d8943ccf10`, #4258 `5adfc40032`. Rows describing open PRs +reflect those heads and go stale as the PRs are updated; the merged table does +not. diff --git a/packages/rs-platform-wallet-ffi/README.md b/packages/rs-platform-wallet-ffi/README.md index 7a94d2a01f9..2380c9a1529 100644 --- a/packages/rs-platform-wallet-ffi/README.md +++ b/packages/rs-platform-wallet-ffi/README.md @@ -175,6 +175,12 @@ Error codes: - `PLATFORM_WALLET_FFI_ERROR_CONTACT_NOT_FOUND` - Contact not found - And more... +The result codes are **public ABI**: their integer values are consumed by the +generated C header and mirrored by the Swift and Kotlin SDKs. Before adding a +new code, read [ERROR_CODE_REGISTRY.md](ERROR_CODE_REGISTRY.md) — it holds the +authoritative integer→name allocation, the rule for claiming the next free +value, and the currently contested allocations across open PRs. + ## Testing Run the test suite: From 74ea976f804e5b67ce6053b565681b70f819f968 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Sat, 1 Aug 2026 15:18:58 -0400 Subject: [PATCH 02/22] docs(ffi): record the 29/30 resolution as landed; add missing 27/28 collisions The 29 collision is resolved and the renumber has now landed on #4185's branch: #4184 keeps 29 (ErrorAssetLockInsufficientFunds), #4185 takes 30 (ErrorReservationWalletMismatch). Table rows updated to match the code. Fixes the "30 is both free and assigned" inconsistency: the next-free line claimed 27-33 were claimed while the table showed 30 unallocated. 30 is now genuinely allocated to #4185, so the two agree. Adds allocations the survey had omitted, verified 2026-08-01 by reading error.rs at the head of all 62 open PRs: - #3968 numbers 26/27/28 (Persister* + a pre-merge TransactionBroadcastRejected) -> contradicts merged ABI at 26 and collides with #4185 at 27 and 28 - #3954 numbers ErrorShutdownIncomplete = 27 -> collides with #4185 at 27 - #4259 carries ErrorSigningKeyUnavailable = 31, inherited from #4183 rather than a new allocation The same sweep confirms no open PR anywhere defines a code 30. --- .../ERROR_CODE_REGISTRY.md | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 3d1c883b189..a5fcde291f2 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -76,7 +76,9 @@ These are shipped ABI. Do not renumber. | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next free integer: 34** (see the proposed table; 27–33 are claimed). +**Next free integer: 34** — 27–33 are all claimed in the proposed table below. +(Before the 29/30 resolution landed this line disagreed with the table, which +still showed 30 as unallocated; 30 is now allocated to #4185 and the two agree.) ## Proposed allocations (open PRs) @@ -87,9 +89,8 @@ this file. | ---: | --- | --- | --- | | 27 | `ErrorStaleReservationToken` | #4185 | In review (also carried by #4256) | | 28 | `ErrorReservationTokenConsumed` | #4185 | In review (also carried by #4256) | -| 29 | `ErrorReservationWalletMismatch` | #4185 | **Collision** — see below | -| 29 | `ErrorAssetLockInsufficientFunds` | #4184 | **Collision** — see below | -| 30 | — | — | **Unallocated.** Reserved in sibling comments only; see below | +| 29 | `ErrorAssetLockInsufficientFunds` | #4184 | In review — **keeps 29** (collision resolved) | +| 30 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 29 → 30** (collision resolved; #4256 must inherit) | | 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204) | | 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | | 33 | `ErrorTransactionSigning` | #4256 | In review | @@ -99,26 +100,56 @@ Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code: #4186, ## Contested and pending -### 29 — `ErrorReservationWalletMismatch` (#4185) vs `ErrorAssetLockInsufficientFunds` (#4184) +### 29 — RESOLVED: #4184 keeps 29; #4185 moved to 30 -Both PR heads define code 29. This is the known collision: review on #4185 -directed that PR to keep #4184's `29 = ErrorAssetLockInsufficientFunds` and move -`ErrorReservationWalletMismatch` to 30. That renumber has not landed on #4185's -head, and #4256 (stacked downstream) carries the pre-renumber `29`. +Both PR heads defined code 29. Resolution of record: **#4184 keeps +`29 = ErrorAssetLockInsufficientFunds`; #4185 moves `ErrorReservationWalletMismatch` +to 30.** -Resolution of record: **#4184 keeps 29; #4185 moves to 30**, propagated through -the Rust enum, the FFI `From` mapping, Swift `PlatformWalletResult`, Kotlin -`DashSdkError` (+ `DashSdkErrorTest`), and the JNI rustdoc — plus #4256, which -inherits the value. +**This renumber has now landed on #4185's branch**, propagated through every +site: the Rust enum discriminant and its three rustdoc cross-references +(`rs-platform-wallet-ffi/src/error.rs`), the two `signed_payment.rs` doc +references, the JNI rustdoc (`rs-unified-sdk-jni/src/wallet_manager.rs`), Swift +`PlatformWalletResultCode`'s raw value + doc +(`PlatformWalletResult.swift`), and Kotlin's `fromPlatformWalletNative` branch, +class KDoc, code-98 comment (`DashSdkError.kt`), `WalletManagerNative.kt` KDoc, +and the `DashSdkErrorTest` offset assertion. -### 30 — reserved in comments for a variant that no longer exists +Both Swift `switch`es are symbolic — `init(ffi:)` matches cbindgen-generated +`PLATFORM_WALLET_FFI_RESULT_CODE_*` constants, so only the enum's raw value +carried the number. + +**Still outstanding:** #4256 is stacked downstream and its head still carries the +pre-renumber `29`; it must adopt 30 when it rebases. #4196 likewise (see below). + +### 30 — allocated to #4185; the old "consent code" reservation was stale `ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in in-tree comments on #4183, #4204, and #4247/#4256's numbering rationale. It is **not defined anywhere** — #4184, the PR that would have introduced it, does not -contain it after a re-scope. 30 is therefore free, and is the slot the #4185 -renumber above should take. The stale "reserved for the consent code" comments -should be dropped by whichever PR touches them next. +contain it after a re-scope. + +Verified 2026-08-01 by reading `packages/rs-platform-wallet-ffi/src/error.rs` at +the head of **every one of the 62 open PRs**: no PR anywhere defines a code 30. +30 was therefore genuinely free, and #4185 has taken it. The stale "reserved for +the consent code" comments should be dropped by whichever PR touches them next. + +### 27 / 28 — #3968 and #3954 collide with #4185's reservation trio + +Found by the same 2026-08-01 sweep; these were missing from the tables above. + +- **#3968** (`5931df745a`) numbers `ErrorPersisterTransient = 26`, + `ErrorPersisterFatal = 27`, `ErrorTransactionBroadcastRejected = 28`. It + branched before `26 = ErrorTransactionBroadcastRejected` merged, so it both + contradicts merged ABI at 26 **and** collides with #4185 at 27 and 28. +- **#3954** (`93d0bd49b7`) numbers `ErrorShutdownIncomplete = 27`, colliding with + #4185's `ErrorStaleReservationToken = 27`. +- **#4259** (`4270d827c2`) carries `ErrorSigningKeyUnavailable = 31` — the same + number and name as #4183, i.e. inherited rather than a new allocation, like + #4204. + +Both #3968 and #3954 need a rebase onto current `v4.2-dev` and fresh integers +from the frontier below; #4185's 27/28 are the older claim and should stand. ### 26 — `ErrorStaleReservationToken` on #4196 collides with merged ABI @@ -149,7 +180,8 @@ the same thing in both enums. ## Survey provenance Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c` and the following PR -heads: #4183 `2cd948331b`, #4184 `a9e418af50`, #4185 `7d85953c2a`, #4186 +heads: #3954 `93d0bd49b7`, #3968 `5931df745a`, #4183 `2cd948331b`, #4184 +`a9e418af50`, #4185 `0b0d5c76d6` (post-renumber), #4259 `4270d827c2`, #4186 `6f7abbadc1`, #4191 `8acb0bd14c`, #4194 `9efc0b7e3a`, #4195 `4f2eb06d64`, #4196 `ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `72c000dcfd`, #4251 `176f8ed3eb`, #4256 `d8943ccf10`, #4258 `5adfc40032`. Rows describing open PRs From 5cab764b6da96a2b01d4d7af25d61c993473639f Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Sat, 1 Aug 2026 21:04:33 -0400 Subject: [PATCH 03/22] docs(ffi): give the unlisted allocations rows; correct provenance; record #4196 scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clears the two review blockers on #4261 and re-syncs the registry with what the code on each branch actually does, re-read at every head rather than trusted from this file. Blocker (a) — #3968 / #3954 / #4259 were described in prose but had no rows, which is exactly what rule 2 forbids. They now have them: - A "Non-conforming allocations" table for #3968 (26/27/28) and #3954 (27). These are deliberately kept out of the proposed table: each row is a claim to be withdrawn and reissued, not an allocation of record. - An inherited-code table for the 31 that #4204 and #4259 carry but did not allocate (#4183 owns it), so it is not double-counted. - #4196 is recorded as claiming no integer at all: it routes a new token-less `StaleReservation` variant through the existing `ErrorStaleReservationToken`. The #3968 half is the serious one and is called out as such. Its 28 is not a new claim — it *moves the already-shipped* `ErrorTransactionBroadcastRejected` off 26 to make room for its own persister code. Rule 3 forbids that: a host compiled against merged ABI returns 26 for a broadcast rejection, and after #3968 the same condition returns 28 while 26 means a transient persister failure. Neither branch's diff shows the contradiction. Blocker (b) — 30 marked both free and assigned was already resolved by the preceding commit; verified consistent here (30 is allocated to #4185 throughout, frontier is 34, and the one remaining "genuinely free" is past tense explaining why #4185 could take it). Also corrected, all verified against the branches: - Survey provenance had #4185 at `0b0d5c76d6` labelled "(post-renumber)". Wrong twice: that commit is the *parent* of the renumber `d854debb`, and the head has since moved to `6c37e8679e`. #4184, #4247 and #4256 SHAs refreshed too. - #4256 has now taken 30 (`9481e5783b`) and dropped its stale "30 is reserved for the consent code" rationale; the equivalent comments on #4183 and #4204 are flagged as still present. - #4184 has a comment-only drift: it reserves "Codes 27-28" but names three codes. Correct when the trio was 27/28/29; it is now 27/28/30. Its discriminant is right and is the resolution of record — only the prose is stale, and #4184 is left untouched. - The #4196 section now records why the restack has not happened: its three own commits conflict in 3 files / 10 hunks against #4185's head, and the registry redesign underneath it (mandatory `registered_height`, new `WalletRemoved` variant, owner-stamped funding token) makes it author work rather than conflict resolution. Its trio numbers come from the #4185 copy it carries, so the restack fixes 28 -> 30 for free; the number #4196 itself must chase is 27, not 30. Verified: cargo fmt --all -- --check clean; cargo test -p platform-wallet-ffi -p platform-wallet = 738 passed / 0 failed. Docs-only change. --- .../ERROR_CODE_REGISTRY.md | 146 ++++++++++++++++-- 1 file changed, 133 insertions(+), 13 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index a5fcde291f2..27259d8b145 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -90,7 +90,7 @@ this file. | 27 | `ErrorStaleReservationToken` | #4185 | In review (also carried by #4256) | | 28 | `ErrorReservationTokenConsumed` | #4185 | In review (also carried by #4256) | | 29 | `ErrorAssetLockInsufficientFunds` | #4184 | In review — **keeps 29** (collision resolved) | -| 30 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 29 → 30** (collision resolved; #4256 must inherit) | +| 30 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 29 → 30** (collision resolved; #4256 has inherited it, #4196 inherits on restack) | | 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204) | | 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | | 33 | `ErrorTransactionSigning` | #4256 | In review | @@ -98,6 +98,40 @@ this file. Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code: #4186, #4191, #4194, #4195, #4240, #4251, #4258. +Two more carry a code they did not allocate, inherited from the PR they are +stacked on rather than claimed fresh — they must not be read as a second claim +on the number: + +| Code | Name | Carried by | Allocated to | +| ---: | --- | --- | --- | +| 31 | `ErrorSigningKeyUnavailable` | #4204, #4259 | #4183 | + +#4196 also claims no new integer: it adds a token-less +`PlatformWalletError::StaleReservation` variant and deliberately routes it +through the **existing** `ErrorStaleReservationToken`, so it allocates nothing +and only has to follow that code's number (see below). + +### Non-conforming allocations (rebase required) + +These branches allocate into the same range from a stale base. They are listed +here rather than in the proposed table because their numbers cannot stand as +written — each row is a claim to be **withdrawn and reissued**, not an +allocation of record. + +| Code | Name | Owning PR | Conflict | +| ---: | --- | --- | --- | +| 26 | `ErrorPersisterTransient` | #3968 | Contradicts **merged ABI** — 26 is `ErrorTransactionBroadcastRejected` | +| 27 | `ErrorPersisterFatal` | #3968 | Collides with #4185 `ErrorStaleReservationToken` | +| 28 | `ErrorTransactionBroadcastRejected` | #3968 | **Renumbers a shipped code** 26 → 28 — forbidden by rule 3 | +| 27 | `ErrorShutdownIncomplete` | #3954 | Collides with #4185 `ErrorStaleReservationToken` | + +#3968 is the serious one: rule 3 forbids renumbering a code that has shipped, +and `ErrorTransactionBroadcastRejected = 26` is merged ABI. Moving it to 28 +would silently reinterpret every 26 an already-compiled host returns. #3968 must +keep 26 where it is and take fresh integers from the frontier for its two +persister codes; #3954 likewise for its shutdown code. #4185's 27/28 are the +older claim and stand. + ## Contested and pending ### 29 — RESOLVED: #4184 keeps 29; #4185 moved to 30 @@ -119,8 +153,20 @@ Both Swift `switch`es are symbolic — `init(ffi:)` matches cbindgen-generated `PLATFORM_WALLET_FFI_RESULT_CODE_*` constants, so only the enum's raw value carried the number. -**Still outstanding:** #4256 is stacked downstream and its head still carries the -pre-renumber `29`; it must adopt 30 when it rebases. #4196 likewise (see below). +**#4256 has now adopted 30 as well** (`9481e5783b`), through the same mirror set +minus the code-98 comment, which that branch does not carry: the enum +discriminant and its rustdoc cross-reference, the `signed_payment.rs` doc, the +JNI rustdoc, the Swift raw value, and Kotlin's `fromPlatformWalletNative` branch, +class KDoc, `WalletManagerNative` KDoc and `DashSdkErrorTest` offset assertion. +#4256's other codes are untouched: it keeps 32 (shared with #4247) and 33. + +Note that neither #4184 nor #4256 was ever blocked by CI on this. Both are +MERGEABLE with green checks, because two branches assigning the same +discriminant produce no textual conflict — the collision surfaces only as an +E0081 after a textual merge, or silently as a wrong error code on the host. +That is the whole reason this file exists. + +**Still outstanding:** #4196 (see below). ### 30 — allocated to #4185; the old "consent code" reservation was stale @@ -134,30 +180,92 @@ the head of **every one of the 62 open PRs**: no PR anywhere defines a code 30. 30 was therefore genuinely free, and #4185 has taken it. The stale "reserved for the consent code" comments should be dropped by whichever PR touches them next. +#4256 has done so on its own branch (`9481e5783b`): its +`ErrorTransactionSigning` numbering rationale no longer describes 30 as reserved +for the consent code, and now names 30 as `ErrorReservationWalletMismatch`. The +equivalent stale comments on #4183 and #4204 are still there. + +#4184 has a smaller drift of the same kind, left in place because that branch is +settled and the drift is comment-only. Its reservation note reads "Codes 27-28 +are reserved" but then names **three** codes — `ErrorStaleReservationToken` / +`ErrorReservationTokenConsumed` / `ErrorReservationWalletMismatch`. That was +correct when the trio was 27/28/29 and #4184 was avoiding the range; after the +renumber the trio is 27/28/**30**, so the note should read "Codes 27-28 and 30". +The discriminant itself (`ErrorAssetLockInsufficientFunds = 29`) is correct and +is the resolution of record — only the prose is stale. + ### 27 / 28 — #3968 and #3954 collide with #4185's reservation trio -Found by the same 2026-08-01 sweep; these were missing from the tables above. +Found by the same 2026-08-01 sweep. These now have rows — see **Non-conforming +allocations** above for #3968 and #3954, and the inherited-code table for #4259. +The detail behind those rows: - **#3968** (`5931df745a`) numbers `ErrorPersisterTransient = 26`, `ErrorPersisterFatal = 27`, `ErrorTransactionBroadcastRejected = 28`. It branched before `26 = ErrorTransactionBroadcastRejected` merged, so it both contradicts merged ABI at 26 **and** collides with #4185 at 27 and 28. + + The 28 is the more serious half and is easy to miss, because it does not look + like an allocation at all: #3968 is not claiming 28 for something new, it is + *moving a code that has already shipped* out of the way of its own 26. Rule 3 + forbids that outright. A host compiled against merged ABI returns 26 for a + broadcast rejection; after #3968 the same condition returns 28, and 26 means + a transient persister failure. Nothing in either branch's diff shows the + contradiction. #3968 must leave 26 alone and take fresh integers for both + persister codes. - **#3954** (`93d0bd49b7`) numbers `ErrorShutdownIncomplete = 27`, colliding with - #4185's `ErrorStaleReservationToken = 27`. + #4185's `ErrorStaleReservationToken = 27`. Straightforward by comparison — a + proposed-vs-proposed collision, resolvable by renumbering either side. #4185's + claim is older and stands. - **#4259** (`4270d827c2`) carries `ErrorSigningKeyUnavailable = 31` — the same number and name as #4183, i.e. inherited rather than a new allocation, like - #4204. + #4204. No conflict; recorded so the number is not double-counted. Both #3968 and #3954 need a rebase onto current `v4.2-dev` and fresh integers -from the frontier below; #4185's 27/28 are the older claim and should stand. +from the frontier (34+); #4185's 27/28 are the older claim and should stand. ### 26 — `ErrorStaleReservationToken` on #4196 collides with merged ABI #4196 (stacked on #4185) branched before `26 = ErrorTransactionBroadcastRejected` merged, and its head numbers the reservation trio **26 / 27 / 28**. Merging it as -it stands would give 26 two meanings and would contradict #4185's own 27 / 28 / 29 -for the same three names. #4196 needs a rebase onto current `v4.2-dev` and must -adopt whatever numbering #4185 lands with. No new integers are needed for it. +it stands would give 26 two meanings and would contradict #4185's own +27 / 28 / 30 for the same three names. #4196 needs a rebase and must adopt +whatever numbering #4185 lands with. No new integers are needed for it. + +**All three of those numbers come from the copy of #4185 that #4196 carries, not +from #4196's own commits.** Restacking onto #4185's head therefore fixes the +trio for free — including `ErrorReservationWalletMismatch` 28 → 30, which #4196 +never had to move itself. The one number #4196 does own is a doc reference: its +`StaleReservation` variant and the matching Kotlin KDoc both cite +`ErrorStaleReservationToken` as **26**, and that becomes **27** post-restack. +So the number #4196 must chase is 27, not 30. + +**The restack is not mechanical — it is blocked on a redesign.** Rebasing +#4196's three own commits (`2d29451d06`, `c64af1a6eb`, `ea4f783490`) onto +#4185's head `6c37e8679e` conflicts in three files (10 hunks): `error.rs` (3), +`wallet/core/broadcast.rs` (1), `wallet/signed_payment_registry.rs` (6). The +`error.rs` hunks are genuinely mechanical. The other two are not, because #4185 +redesigned the registry underneath #4196 after it branched: + +- `registered_height` changed from `Option` to a mandatory `u32`. #4196's + age guard is built around the `None` case meaning "guard disabled"; that case + no longer exists. +- #4185 added a `SignedPaymentError::WalletRemoved` variant and an + owner-stamped `funding_reservation_token` field. #4196 predates both. +- #4196 wants to *move* `RESERVATION_MAX_AGE_BLOCKS` and `reservation_expired` + into `wallet/reservations.rs` so the V2 handle path can share them. #4185 has + since rewritten both in place, with new generation-binding rationale. +- #4196's V2 guard documents "leave the stale reservation for the TTL rather + than release by outpoint". #4185 now releases by owner-guarded *token*, which + changes that rationale rather than conflicting with it textually. + +Resolving this means re-deriving #4196's age guard against the new registry +shape, with real semantic decisions to make (does the V2 guard now release by +owner token? what replaces the `None`-disables-the-guard branch?). That is +author work, not conflict resolution, and it is why this was left rather than +forced through. shumkov's 07-24 request to restack onto #4185's post-renumber +head is actionable in the sense that the base now exists — but the restack +itself needs #4196's author. ### 31 vs 33 — two signing-related codes, deliberately distinct @@ -181,9 +289,21 @@ the same thing in both enums. Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c` and the following PR heads: #3954 `93d0bd49b7`, #3968 `5931df745a`, #4183 `2cd948331b`, #4184 -`a9e418af50`, #4185 `0b0d5c76d6` (post-renumber), #4259 `4270d827c2`, #4186 +`bd19a3e020`, #4185 `6c37e8679e` (post-renumber), #4259 `4270d827c2`, #4186 `6f7abbadc1`, #4191 `8acb0bd14c`, #4194 `9efc0b7e3a`, #4195 `4f2eb06d64`, #4196 -`ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `72c000dcfd`, #4251 -`176f8ed3eb`, #4256 `d8943ccf10`, #4258 `5adfc40032`. Rows describing open PRs +`ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `0dcdc743e7`, #4251 +`176f8ed3eb`, #4256 `9481e5783b`, #4258 `5adfc40032`. Rows describing open PRs reflect those heads and go stale as the PRs are updated; the merged table does not. + +Four of these were corrected on 2026-08-01 after the heads moved. The +`#4185 0b0d5c76d6 (post-renumber)` this list previously carried was wrong twice +over: `0b0d5c76d6` is the *parent* of the renumber commit `d854debb`, so it was +pre-renumber, and the branch has since advanced to `6c37e8679e`. #4184 was +recorded at `a9e418af50` (now `bd19a3e020`), #4247 at `72c000dcfd` (now +`0dcdc743e7`), and #4256 at `d8943ccf10` (now `9481e5783b`, which carries the +29 → 30 move). + +The 26 / 27 / 28 / 31 claims attributed to #3968, #3954 and #4259 were +re-verified on 2026-08-01 by reading `error.rs` at each of those three heads +directly, not from this file. From 4dab3963525d94ea62a60acba49596b16f76addf Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Sun, 2 Aug 2026 23:04:42 -0400 Subject: [PATCH 04/22] docs(ffi): record #4268's merged 27 and the trio's move to 34-36 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dashpay/platform#4268 merged `ErrorShutdownIncomplete = 27` into the v4.2-dev ABI on 2026-08-02, taking the number #4185 had held. #4185 and #4256 moved the deferred-token trio to the contiguous block 34-36 in response. Registry changes: * 27 enters the merged table, owned by #4268. * The proposed table moves the trio to 34/35/36 and marks 28 and 30 free but deliberately not reissued. Next free integer is now 37. * New "Collision history" section records all three numberings of the trio (26/27/28 -> 27/28/30 -> 34/35/36) and, more usefully, corrects this file's own reasoning: on 2026-08-01 it recorded #3954's `ErrorShutdownIncomplete = 27` as a non-conforming claim that had to be withdrawn because #4185's claim was older. Seniority among open PRs does not decide an ABI number — merging does. #3954 was closed, its work landed as #4268, and 27 is now merged ABI. The trio therefore moved above every claimed number rather than into the next free gap, so nothing currently in flight can hit it again. * #3968's 27 is re-characterised: it was a proposed-vs-proposed collision, and is now a contradiction of merged ABI. Its frontier is 37+. * #4196 is now two moves behind at 26/27/28; the doc reference it owns has to chase 34, not 27. * Records a mirror gap found while grepping for this move: #4256 declares `ErrorTransactionBuild` (32) and `ErrorTransactionSigning` (33) in Rust and maps both in Kotlin, but declares neither in Swift, so both reach Swift hosts as `.errorUnknown`. Rule 5's Swift clause; left for that PR's author. * Provenance re-verified against v4.2-dev `5d68612a45`, including the check that 32 and 33 were already taken — which is why the trio went to 34-36 and not 32-34. Co-Authored-By: Claude Opus 4.8 --- .../ERROR_CODE_REGISTRY.md | 210 ++++++++++++------ 1 file changed, 141 insertions(+), 69 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 27259d8b145..376a3f38421 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -73,12 +73,16 @@ These are shipped ABI. Do not renumber. | 24 | `ErrorAssetLockAlreadyConsumed` | | | 25 | `ErrorAssetLockFundingMismatch` | | | 26 | `ErrorTransactionBroadcastRejected` | Merged in `9302c62e8b`; took a number several open branches had been treating as free | +| 27 | `ErrorShutdownIncomplete` | Merged 2026-08-02 by **#4268** (`429667e723`). A quiesce/drain barrier missed its budget. **Took the number #4185 had held since before this file existed** — see the collision history below | | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next free integer: 34** — 27–33 are all claimed in the proposed table below. -(Before the 29/30 resolution landed this line disagreed with the table, which -still showed 30 as unallocated; 30 is now allocated to #4185 and the two agree.) +**Next free integer: 37** — 27–36 are claimed (27 merged; 29, 31–36 in the +proposed table below). **28 and 30 are free**: #4185 and #4256 vacated them when +the reservation trio moved to 34–36, but they are deliberately left unclaimed +rather than back-filled, so that the trio stays contiguous and no number is +reused within a single review cycle. A new code should take 37 unless it has a +reason to sit next to something. ## Proposed allocations (open PRs) @@ -87,13 +91,15 @@ this file. | Code | Name | Owning PR | Status | | ---: | --- | --- | --- | -| 27 | `ErrorStaleReservationToken` | #4185 | In review (also carried by #4256) | -| 28 | `ErrorReservationTokenConsumed` | #4185 | In review (also carried by #4256) | +| 28 | *(free)* | — | Vacated by #4185/#4256 on 2026-08-02; not reissued | | 29 | `ErrorAssetLockInsufficientFunds` | #4184 | In review — **keeps 29** (collision resolved) | -| 30 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 29 → 30** (collision resolved; #4256 has inherited it, #4196 inherits on restack) | -| 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204) | +| 30 | *(free)* | — | Vacated by #4185/#4256 on 2026-08-02; not reissued | +| 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204, #4259) | | 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | | 33 | `ErrorTransactionSigning` | #4256 | In review | +| 34 | `ErrorStaleReservationToken` | #4185 | In review — **moved 27 → 34** (also carried by #4256; #4196 inherits on restack) | +| 35 | `ErrorReservationTokenConsumed` | #4185 | In review — **moved 28 → 35** (also carried by #4256) | +| 36 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 30 → 36** (also carried by #4256) | Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code: #4186, #4191, #4194, #4195, #4240, #4251, #4258. @@ -121,44 +127,32 @@ allocation of record. | Code | Name | Owning PR | Conflict | | ---: | --- | --- | --- | | 26 | `ErrorPersisterTransient` | #3968 | Contradicts **merged ABI** — 26 is `ErrorTransactionBroadcastRejected` | -| 27 | `ErrorPersisterFatal` | #3968 | Collides with #4185 `ErrorStaleReservationToken` | +| 27 | `ErrorPersisterFatal` | #3968 | Contradicts **merged ABI** — 27 is #4268's `ErrorShutdownIncomplete` (was a #4185 collision until 2026-08-02) | | 28 | `ErrorTransactionBroadcastRejected` | #3968 | **Renumbers a shipped code** 26 → 28 — forbidden by rule 3 | -| 27 | `ErrorShutdownIncomplete` | #3954 | Collides with #4185 `ErrorStaleReservationToken` | + +#3954's `ErrorShutdownIncomplete = 27` used to sit in this table. It is gone +because that claim **won**: #3954 was closed and superseded by **#4268**, which +merged 27 into `v4.2-dev` on 2026-08-02. See the collision history below. #3968 is the serious one: rule 3 forbids renumbering a code that has shipped, and `ErrorTransactionBroadcastRejected = 26` is merged ABI. Moving it to 28 would silently reinterpret every 26 an already-compiled host returns. #3968 must -keep 26 where it is and take fresh integers from the frontier for its two -persister codes; #3954 likewise for its shutdown code. #4185's 27/28 are the -older claim and stand. +keep 26 where it is and take fresh integers from the frontier (37+) for its two +persister codes. Its 27 is now doubly wrong: 27 is merged ABI +(`ErrorShutdownIncomplete`), so rule 3 protects it too. ## Contested and pending -### 29 — RESOLVED: #4184 keeps 29; #4185 moved to 30 +### 29 — RESOLVED: #4184 keeps 29 (#4185 moved away, twice) Both PR heads defined code 29. Resolution of record: **#4184 keeps `29 = ErrorAssetLockInsufficientFunds`; #4185 moves `ErrorReservationWalletMismatch` to 30.** -**This renumber has now landed on #4185's branch**, propagated through every -site: the Rust enum discriminant and its three rustdoc cross-references -(`rs-platform-wallet-ffi/src/error.rs`), the two `signed_payment.rs` doc -references, the JNI rustdoc (`rs-unified-sdk-jni/src/wallet_manager.rs`), Swift -`PlatformWalletResultCode`'s raw value + doc -(`PlatformWalletResult.swift`), and Kotlin's `fromPlatformWalletNative` branch, -class KDoc, code-98 comment (`DashSdkError.kt`), `WalletManagerNative.kt` KDoc, -and the `DashSdkErrorTest` offset assertion. - -Both Swift `switch`es are symbolic — `init(ffi:)` matches cbindgen-generated -`PLATFORM_WALLET_FFI_RESULT_CODE_*` constants, so only the enum's raw value -carried the number. - -**#4256 has now adopted 30 as well** (`9481e5783b`), through the same mirror set -minus the code-98 comment, which that branch does not carry: the enum -discriminant and its rustdoc cross-reference, the `signed_payment.rs` doc, the -JNI rustdoc, the Swift raw value, and Kotlin's `fromPlatformWalletNative` branch, -class KDoc, `WalletManagerNative` KDoc and `DashSdkErrorTest` offset assertion. -#4256's other codes are untouched: it keeps 32 (shared with #4247) and 33. +**#4184's 29 is settled and has not moved.** #4185's third code moved to 30 to +clear it, and then — with the rest of the trio — to **36** when #4268 merged 27 +(see the collision history above). 30 is free again as a result. Nothing about +this section's resolution changed: 29 is #4184's. Note that neither #4184 nor #4256 was ever blocked by CI on this. Both are MERGEABLE with green checks, because two branches assigning the same @@ -168,7 +162,7 @@ That is the whole reason this file exists. **Still outstanding:** #4196 (see below). -### 30 — allocated to #4185; the old "consent code" reservation was stale +### 30 — free again; the old "consent code" reservation was stale `ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in in-tree comments on #4183, #4204, and #4247/#4256's numbering rationale. It is @@ -177,24 +171,29 @@ contain it after a re-scope. Verified 2026-08-01 by reading `packages/rs-platform-wallet-ffi/src/error.rs` at the head of **every one of the 62 open PRs**: no PR anywhere defines a code 30. -30 was therefore genuinely free, and #4185 has taken it. The stale "reserved for -the consent code" comments should be dropped by whichever PR touches them next. +30 was therefore genuinely free, and #4185 took it — then vacated it again on +2026-08-02 when the trio moved to 34–36. **30 is free once more, and is +deliberately not being reissued** (see the collision history above). The stale +"reserved for the consent code" comments should be dropped by whichever PR +touches them next. -#4256 has done so on its own branch (`9481e5783b`): its -`ErrorTransactionSigning` numbering rationale no longer describes 30 as reserved -for the consent code, and now names 30 as `ErrorReservationWalletMismatch`. The -equivalent stale comments on #4183 and #4204 are still there. +#4256 has done so on its own branch: its `ErrorTransactionSigning` numbering +rationale no longer describes 30 as reserved for the consent code. As of +`8febac177c` that rationale names #4268 as the owner of 27 and records where the +trio went. The equivalent stale comments on #4183 and #4204 are still there. #4184 has a smaller drift of the same kind, left in place because that branch is settled and the drift is comment-only. Its reservation note reads "Codes 27-28 are reserved" but then names **three** codes — `ErrorStaleReservationToken` / `ErrorReservationTokenConsumed` / `ErrorReservationWalletMismatch`. That was -correct when the trio was 27/28/29 and #4184 was avoiding the range; after the -renumber the trio is 27/28/**30**, so the note should read "Codes 27-28 and 30". -The discriminant itself (`ErrorAssetLockInsufficientFunds = 29`) is correct and -is the resolution of record — only the prose is stale. +correct when the trio was 27/28/29 and #4184 was avoiding the range. It is now +doubly stale: the trio is at **34-36**, and 27 belongs to #4268's merged +`ErrorShutdownIncomplete`. The note should simply say that 29 sits below the +trio's 34-36 block. The discriminant itself +(`ErrorAssetLockInsufficientFunds = 29`) is correct and is the resolution of +record — only the prose is stale, and #4184 need not move. -### 27 / 28 — #3968 and #3954 collide with #4185's reservation trio +### 27 / 28 — #3968 still collides; #3954's claim merged as #4268 Found by the same 2026-08-01 sweep. These now have rows — see **Non-conforming allocations** above for #3968 and #3954, and the inherited-code table for #4259. @@ -213,36 +212,41 @@ The detail behind those rows: a transient persister failure. Nothing in either branch's diff shows the contradiction. #3968 must leave 26 alone and take fresh integers for both persister codes. -- **#3954** (`93d0bd49b7`) numbers `ErrorShutdownIncomplete = 27`, colliding with - #4185's `ErrorStaleReservationToken = 27`. Straightforward by comparison — a - proposed-vs-proposed collision, resolvable by renumbering either side. #4185's - claim is older and stands. +- **#3954** (`93d0bd49b7`) numbered `ErrorShutdownIncomplete = 27`. This file + previously called that a proposed-vs-proposed collision and said #4185's older + claim should stand. **That was wrong, and it resolved the other way.** #3954 + was closed; its work landed as **#4268**, which merged 27 into `v4.2-dev` on + 2026-08-02. #4185 and #4256 moved their trio to 34–36 in response. Merging + decides an ABI number; being the older open claim does not. - **#4259** (`4270d827c2`) carries `ErrorSigningKeyUnavailable = 31` — the same number and name as #4183, i.e. inherited rather than a new allocation, like #4204. No conflict; recorded so the number is not double-counted. -Both #3968 and #3954 need a rebase onto current `v4.2-dev` and fresh integers -from the frontier (34+); #4185's 27/28 are the older claim and should stand. +#3968 needs a rebase onto current `v4.2-dev` and fresh integers from the +frontier (**37+**). It must leave 26 alone, and 27 is no longer available to it +either — that is merged ABI now. -### 26 — `ErrorStaleReservationToken` on #4196 collides with merged ABI +### 26 — #4196's trio collides with merged ABI (and is now two moves behind) #4196 (stacked on #4185) branched before `26 = ErrorTransactionBroadcastRejected` -merged, and its head numbers the reservation trio **26 / 27 / 28**. Merging it as -it stands would give 26 two meanings and would contradict #4185's own -27 / 28 / 30 for the same three names. #4196 needs a rebase and must adopt -whatever numbering #4185 lands with. No new integers are needed for it. +merged, and its head still numbers the reservation trio **26 / 27 / 28**. It is +now two moves behind: merging it as it stands would give 26 two meanings, give 27 +two meanings against #4268's merged `ErrorShutdownIncomplete`, and contradict +#4185's own **34 / 35 / 36** for the same three names. #4196 needs a rebase and +must adopt whatever numbering #4185 lands with. No new integers are needed for +it. **All three of those numbers come from the copy of #4185 that #4196 carries, not from #4196's own commits.** Restacking onto #4185's head therefore fixes the -trio for free — including `ErrorReservationWalletMismatch` 28 → 30, which #4196 -never had to move itself. The one number #4196 does own is a doc reference: its -`StaleReservation` variant and the matching Kotlin KDoc both cite -`ErrorStaleReservationToken` as **26**, and that becomes **27** post-restack. -So the number #4196 must chase is 27, not 30. +trio for free — including the two moves #4196 never had to make itself. The one +number #4196 does own is a doc reference: its `StaleReservation` variant and the +matching Kotlin KDoc both cite `ErrorStaleReservationToken` as **26**, and that +becomes **34** post-restack. So the number #4196 must chase is 34. **The restack is not mechanical — it is blocked on a redesign.** Rebasing #4196's three own commits (`2d29451d06`, `c64af1a6eb`, `ea4f783490`) onto -#4185's head `6c37e8679e` conflicts in three files (10 hunks): `error.rs` (3), +#4185's head (`6c37e8679e` when this was measured; now `3dec774929`) conflicts +in three files (10 hunks): `error.rs` (3), `wallet/core/broadcast.rs` (1), `wallet/signed_payment_registry.rs` (6). The `error.rs` hunks are genuinely mechanical. The other two are not, because #4185 redesigned the registry underneath #4196 after it branched: @@ -278,6 +282,65 @@ failures, and malformed signature encodings. Both codes are currently allocated. Maintainers may still choose to collapse them; that decision belongs to #4183 and #4256 jointly and should be recorded here. +## Collision history — the 27 / 28 / 30 → 34 / 35 / 36 move + +Recorded because the reservation trio has now been renumbered three times, and +because the reason it kept moving is the failure mode this file exists to catch. + +| When | Trio numbering | Why it moved | +| --- | --- | --- | +| original (#4185, #4196) | 26 / 27 / 28 | — | +| 2026-07 | 27 / 28 / 30 | `26 = ErrorTransactionBroadcastRejected` merged (`9302c62e8b`); 29 went to #4184 by agreement, so the third code took 30 | +| **2026-08-02** | **34 / 35 / 36** | **#4268 merged `ErrorShutdownIncomplete = 27` into the `v4.2-dev` ABI** | + +The third move is the instructive one. On 2026-08-01 this file recorded +#3954's `ErrorShutdownIncomplete = 27` as a *non-conforming* claim that had to +be withdrawn, on the reasoning that #4185's 27 was the older claim and should +stand. That reasoning was wrong in the only way that matters: seniority among +open PRs does not decide an ABI number — **merging does**. #3954 was closed and +its work landed as #4268, which merged 27 first. An unmerged claim, however old, +has no standing against merged ABI (rule 3, read from the other side). + +So the trio moved again, and this time it moved **above every number claimed by +anything** — merged or proposed — rather than into the next free gap: + +* 27 `ErrorShutdownIncomplete` (merged, #4268) +* 29 `ErrorAssetLockInsufficientFunds` (#4184) +* 31 `ErrorSigningKeyUnavailable` (#4183/#4204/#4259) +* 32 `ErrorTransactionBuild` (#4247/#4256) +* 33 `ErrorTransactionSigning` (#4256) + +Taking 34–36 rather than back-filling the vacated 28 and 30 costs two integers +in a space that is nowhere near exhausted, and buys two things: the trio reads +as one contiguous family, and it cannot be hit again by anything currently in +flight. **28 and 30 stay free.** Do not reissue them in this review cycle — a +reviewer who saw the earlier numbering would otherwise find a familiar number +attached to an unfamiliar meaning. + +The move landed on both branches on 2026-08-02: **#4185** (`3dec774929`) and +**#4256** (`8febac177c`), each across the Rust enum discriminants and every +rustdoc cross-reference, the two `signed_payment.rs` doc references, the JNI +rustdoc (`rs-unified-sdk-jni/src/wallet_manager.rs`), the Swift +`PlatformWalletResultCode` raw values, and Kotlin's `fromPlatformWalletNative` +branches, class KDoc, `WalletManagerNative.kt` KDoc and the `DashSdkErrorTest` +offset assertions. Both `switch`es in Swift are symbolic — `init(ffi:)` matches +cbindgen `PLATFORM_WALLET_FFI_RESULT_CODE_*` constants — so only the enum's raw +values carried a number there. + +Neither branch's CI could have caught the collision, for the reason given at the +top of this file: a duplicate discriminant across two branches produces no +textual conflict. Both were MERGEABLE and green throughout. + +### Known mirror gap on #4256 (not a numbering issue) + +Noted while grepping the mirrors for this move: #4256 declares +`ErrorTransactionBuild = 32` and `ErrorTransactionSigning = 33` in Rust and maps +both in Kotlin, but its Swift `PlatformWalletResultCode` declares **neither** — +no `case`, and no arm in `init(ffi:)`, so both fall into that switch's +`default:` and reach Swift hosts as `.errorUnknown`, losing their identity. That +is rule 5's Swift clause. Left for #4256's author rather than folded into the +renumber; it is a missing mirror, not a wrong number. + ## Sibling FFI crates `rs-sdk-ffi`'s `DashSDKErrorCode` (`packages/rs-sdk-ffi/src/error.rs`) is a @@ -287,14 +350,23 @@ the same thing in both enums. ## Survey provenance -Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c` and the following PR -heads: #3954 `93d0bd49b7`, #3968 `5931df745a`, #4183 `2cd948331b`, #4184 -`bd19a3e020`, #4185 `6c37e8679e` (post-renumber), #4259 `4270d827c2`, #4186 -`6f7abbadc1`, #4191 `8acb0bd14c`, #4194 `9efc0b7e3a`, #4195 `4f2eb06d64`, #4196 -`ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `0dcdc743e7`, #4251 -`176f8ed3eb`, #4256 `9481e5783b`, #4258 `5adfc40032`. Rows describing open PRs -reflect those heads and go stale as the PRs are updated; the merged table does -not. +Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c`, and **re-verified +2026-08-02 against `v4.2-dev` at `5d68612a45`**, which is where +`ErrorShutdownIncomplete = 27` (#4268, `429667e723`) entered the merged table. +The 2026-08-02 pass re-read the added discriminants at the head of every open PR +that touches `error.rs`, `DashSdkError.kt` or `PlatformWalletResult.swift` +(#3968, #4183, #4184, #4185, #4186, #4191, #4194, #4195, #4196, #4204, #4243, +#4247, #4256, #4259) and confirmed the only claims in the 27–36 range are the +ones tabled above — in particular that 32 and 33 were **already taken** by +#4247/#4256, which is why the trio went to 34–36 rather than 32–34. + +PR heads of record: #3954 `93d0bd49b7` (closed), #3968 `5931df745a`, #4183 +`2cd948331b`, #4184 `bd19a3e020`, **#4185 `3dec774929`** (post-34/35/36 move), +#4186 `6f7abbadc1`, #4191 `8acb0bd14c`, #4194 `9efc0b7e3a`, #4195 `4f2eb06d64`, +#4196 `ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `0dcdc743e7`, +#4251 `176f8ed3eb`, **#4256 `8febac177c`** (post-34/35/36 move), #4258 +`5adfc40032`, #4259 `4270d827c2`. Rows describing open PRs reflect those heads +and go stale as the PRs are updated; the merged table does not. Four of these were corrected on 2026-08-01 after the heads moved. The `#4185 0b0d5c76d6 (post-renumber)` this list previously carried was wrong twice From 584746e9cb627e96acd00d88b8307e195595eb71 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Mon, 3 Aug 2026 09:23:30 -0400 Subject: [PATCH 05/22] =?UTF-8?q?docs(ffi):=20registry=20=E2=80=94=20vacat?= =?UTF-8?q?ed=20codes=2028/30=20are=20reserved,=20not=20free;=20one=20allo?= =?UTF-8?q?cation=20frontier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 376a3f38421..0117af83bfa 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -78,7 +78,7 @@ These are shipped ABI. Do not renumber. | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | **Next free integer: 37** — 27–36 are claimed (27 merged; 29, 31–36 in the -proposed table below). **28 and 30 are free**: #4185 and #4256 vacated them when +proposed table below). **28 and 30 are RESERVED (do not reissue)**: #4185 and #4256 vacated them when the reservation trio moved to 34–36, but they are deliberately left unclaimed rather than back-filled, so that the trio stays contiguous and no number is reused within a single review cycle. A new code should take 37 unless it has a @@ -91,9 +91,9 @@ this file. | Code | Name | Owning PR | Status | | ---: | --- | --- | --- | -| 28 | *(free)* | — | Vacated by #4185/#4256 on 2026-08-02; not reissued | +| 28 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 29 | `ErrorAssetLockInsufficientFunds` | #4184 | In review — **keeps 29** (collision resolved) | -| 30 | *(free)* | — | Vacated by #4185/#4256 on 2026-08-02; not reissued | +| 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204, #4259) | | 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | | 33 | `ErrorTransactionSigning` | #4256 | In review | @@ -151,7 +151,7 @@ to 30.** **#4184's 29 is settled and has not moved.** #4185's third code moved to 30 to clear it, and then — with the rest of the trio — to **36** when #4268 merged 27 -(see the collision history above). 30 is free again as a result. Nothing about +(see the collision history above). 30 is vacated (reserved, not reissuable) as a result. Nothing about this section's resolution changed: 29 is #4184's. Note that neither #4184 nor #4256 was ever blocked by CI on this. Both are @@ -162,7 +162,7 @@ That is the whole reason this file exists. **Still outstanding:** #4196 (see below). -### 30 — free again; the old "consent code" reservation was stale +### 30 — vacated (reserved, not reissuable); the old "consent code" reservation was stale `ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in in-tree comments on #4183, #4204, and #4247/#4256's numbering rationale. It is From 98bd7b865fb8ae5a23c450613ef4f981cb9a4beb Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Mon, 3 Aug 2026 14:25:15 -0400 Subject: [PATCH 06/22] docs(ffi): register 37 = ErrorShieldedInviteAlreadyClaimed; record the 32 collision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #4204 allocated 32 without a row here, colliding with #4247's ErrorTransactionBuild. Caught for real during the v41int13 integration as an E0081, not on paper — the first collision this file has actually stopped. #4204 moves to 37; frontier advances to 38. Also records that the code was unmirrored on both hosts, which had Kotlin misclassifying it as ReservationWalletMismatch wherever #4185's 32 was present. Co-Authored-By: Claude Opus 4.8 --- .../ERROR_CODE_REGISTRY.md | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 0117af83bfa..6948879f696 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -77,11 +77,11 @@ These are shipped ABI. Do not renumber. | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next free integer: 37** — 27–36 are claimed (27 merged; 29, 31–36 in the +**Next free integer: 38** — 27–37 are claimed (27 merged; 29, 31–37 in the proposed table below). **28 and 30 are RESERVED (do not reissue)**: #4185 and #4256 vacated them when the reservation trio moved to 34–36, but they are deliberately left unclaimed rather than back-filled, so that the trio stays contiguous and no number is -reused within a single review cycle. A new code should take 37 unless it has a +reused within a single review cycle. A new code should take 38 unless it has a reason to sit next to something. ## Proposed allocations (open PRs) @@ -100,6 +100,7 @@ this file. | 34 | `ErrorStaleReservationToken` | #4185 | In review — **moved 27 → 34** (also carried by #4256; #4196 inherits on restack) | | 35 | `ErrorReservationTokenConsumed` | #4185 | In review — **moved 28 → 35** (also carried by #4256) | | 36 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 30 → 36** (also carried by #4256) | +| 37 | `ErrorShieldedInviteAlreadyClaimed` | #4204 | In review — **moved 32 → 37** (collided with #4247's `ErrorTransactionBuild`; see below) | Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code: #4186, #4191, #4194, #4195, #4240, #4251, #4258. @@ -143,6 +144,40 @@ persister codes. Its 27 is now doubly wrong: 27 is merged ABI ## Contested and pending +### 32 — RESOLVED: #4204 moved to 37 (first collision this file actually caught) + +Found 2026-08-03 while assembling the `v41int13` QA integration. #4204's head +commit `b6992a5dbc` — a review round, not the original feature work — added +`ErrorShieldedInviteAlreadyClaimed = 32` with **no row in this file**, in +direct violation of rule 2. 32 is allocated to `ErrorTransactionBuild` (#4247, +also carried by #4256). + +Unlike every other entry in this section, this one was not a paper conflict: +merging #4204 into an integration that already carried +`ErrorReservationWalletMismatch = 32` produced a hard +`error[E0081]: discriminant value 32 assigned more than once`. Resolution of +record: **#4204 moves 32 → 37**, the frontier. `ErrorTransactionBuild` keeps 32. + +The numbering was the lesser half of the defect. The code was **unmirrored on +both hosts** — absent from Swift's `PlatformWalletResultCode` and from Kotlin's +`fromPlatformWalletNative`. Per rule 5 that means Swift rendered it +`.errorUnknown` (identity lost), while Kotlin fell through to `Generic(32, …)` +— and in any tree carrying #4185's `ErrorReservationWalletMismatch = 32`, +Kotlin actively **misclassified** "shielded invite already claimed" as +"reservation wallet mismatch". That is the exact silently-wrong-error-on-every-host +failure this file's preamble describes, and it landed on the shielded-invite +claim-recovery path (the error is raised from four sites in +`wallet/shielded/operations.rs`, three of them inside the recovery function). + +Fixed on #4204 together with the renumber: typed +`PlatformWallet.ShieldedInviteAlreadyClaimed` (terminal, `isRetryable = false`), +the Swift case and its `init(ffi:)` arm, and a `DashSdkErrorTest` assertion that +pins 37 so a future move off the frontier fails the suite instead of the hosts. + +**Lesson for rule 2:** the violation entered on a *review-round* commit, well +after the PR's numbering had been reviewed and recorded as settled. Re-check +discriminants on every push that touches `error.rs`, not only at first review. + ### 29 — RESOLVED: #4184 keeps 29 (#4185 moved away, twice) Both PR heads defined code 29. Resolution of record: **#4184 keeps From 6645faffa041df93d441261ed11b16b88e703314 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Mon, 3 Aug 2026 19:33:17 -0400 Subject: [PATCH 07/22] docs(ffi): one allocation frontier at 38; complete the open-PR inventory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves the two blocking review findings and the live suggestions on #4261. Blocking — advance #3968's reissue frontier to 38. Code 37 is allocated to #4204, so the branch-specific guidance in the non-conforming section and in the 27/28 detail section could still have sent #3968 to 37 and recreated the collision with ErrorShieldedInviteAlreadyClaimed. Both references now say 38+, and both state that the reserved 28 and 30 are not available either. Blocking — 28 and 30 were labelled RESERVED in the table and the frontier paragraph but "free" in the code-30 section and the collision history. Rule 1 lets a contributor claim a gap this file marks free, so the two labels gave two different allocation frontiers. Everything now says reserved-not-free and cites rule 1 explicitly. Open-PR inventory: verified 2026-08-03 against each PR's file list and the error.rs at its head. Adds #3417, #3549, #3992 and #4243 (all touch the crate without claiming an integer; #4243 maps new wallet errors onto the existing ErrorInvalidParameter). Removes #4240 and #4251, whose heads touch no file under this crate; removes #4258, merged on 2026-08-03; records #4264 as closed with its work carried by #4243. Also in this pass: - #4204's Swift mirror is recorded as PARTIALLY fixed. At d78b940a03 the raw case and its init(ffi:) arm exist, but PlatformWalletError has no typed case and its exhaustive init(result:) has no arm, so the Swift package does not compile as written. Rule 5's Swift clause is not yet satisfied there. - The preamble no longer claims duplicate discriminants are always silent. Two different names on one integer is an E0081 after a merge (that is how the code-32 collision surfaced); the silent case is a meaning moving to a new integer, or an un-updated host mirror. - Code 13 ErrorArithmeticOverflow does have an in-tree producer (shielded_send.rs); the row said it had none. - #3968 is no longer described as simply un-rebased: its head does contain the 2026-08-01 base, it is behind the current base, and a rebase alone fixes nothing because git sees no conflict — the branch must edit its own enum. - Provenance re-read on 2026-08-03 from GitHub rather than carried forward, now as a table with a note per PR. #4183 and #4184 were rebased onto 5d68612a45 today and keep 31 and 29 respectively; their stale in-enum reservation comments were corrected in the same rebase, so the code-30 section now lists #4204 as the only branch still carrying one. - markdownlint: MD018 (18 occurrences) and MD004 (mixed bullet styles) are both clean; MD013 is down to long table rows only. --- .../ERROR_CODE_REGISTRY.md | 292 +++++++++++------- 1 file changed, 185 insertions(+), 107 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 6948879f696..b30490b8232 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -12,10 +12,26 @@ mirrors it as a `RawRepresentable` enum, Kotlin one numbering keeps using that numbering. This file exists because several feature branches allocate into the same -integer range in parallel. A duplicate discriminant in two branches does **not** -produce a textual merge conflict — the second merge silently misclassifies -errors on every host — so allocations have to be reconciled here, in one place, -rather than in each branch's diff. +integer range in parallel, and a duplicate integer across two branches never +produces a textual merge conflict. What happens after the merge depends on the +shape of the duplication, and only one of the two shapes is caught by a +compiler: + +* **Two different variant names on the same integer.** The merged Rust enum has + two variants with one discriminant, so `rustc` refuses it with + `error[E0081]: discriminant value N assigned more than once`. Loud, but only + *after* someone actually merges both branches into one tree — neither + branch's own CI can see it, because neither branch contains both variants. + This is how the code-32 collision below was finally caught. +* **The same meaning moving to a different integer**, or a host mirror left + un-updated. Nothing fails to compile. A shipped host binary keeps the + numbering it was built against, so it silently reads the new integer as + whatever the old one meant — or, for an unmirrored code, loses the identity + entirely (`.errorUnknown` in Swift). This is the failure this file mainly + exists to prevent, and nothing in either branch's diff shows it. + +So allocations have to be reconciled here, in one place, rather than in each +branch's diff. ## Rules @@ -59,7 +75,7 @@ These are shipped ABI. Do not renumber. | 10 | `ErrorInvalidIdentifier` | | | 11 | `ErrorMemoryAllocation` | | | 12 | `ErrorUtf8Conversion` | | -| 13 | `ErrorArithmeticOverflow` | Reserved slot — declared, no in-tree producer; holds the number for the mapping arriving via #3549 | +| 13 | `ErrorArithmeticOverflow` | Produced in-tree by `shielded_send.rs` (the shielded-send amount/fee overflow guard). The variant's own rustdoc still calls it a reserved slot with no producer and credits #3549 with the eventual mapping — that comment is stale and should be corrected by whichever PR touches it next | | 14 | `ErrorNoSelectableInputs` | | | 15 | `ErrorWalletAlreadyExists` | | | 16 | `ErrorShieldedBroadcastFailed` | | @@ -77,12 +93,14 @@ These are shipped ABI. Do not renumber. | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next free integer: 38** — 27–37 are claimed (27 merged; 29, 31–37 in the -proposed table below). **28 and 30 are RESERVED (do not reissue)**: #4185 and #4256 vacated them when -the reservation trio moved to 34–36, but they are deliberately left unclaimed -rather than back-filled, so that the trio stays contiguous and no number is -reused within a single review cycle. A new code should take 38 unless it has a -reason to sit next to something. +**Next allocatable integer: 38** — 27–37 are all claimed (27 merged; 29 and +31–37 in the proposed table below; 28 and 30 reserved). **28 and 30 are +RESERVED, not free**: #4185 and #4256 vacated them when the reservation trio +moved to 34–36, but they are deliberately left unclaimed rather than +back-filled, so that the trio stays contiguous and no number is reused within a +single review cycle. Rule 1's "do not reuse a gap unless this file marks it +free" applies — this file does **not** mark 28 or 30 free, so the frontier is +the only allocation source and a new code takes 38. ## Proposed allocations (open PRs) @@ -102,10 +120,26 @@ this file. | 36 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 30 → 36** (also carried by #4256) | | 37 | `ErrorShieldedInviteAlreadyClaimed` | #4204 | In review — **moved 32 → 37** (collided with #4247's `ErrorTransactionBuild`; see below) | -Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code: #4186, -#4191, #4194, #4195, #4240, #4251, #4258. +Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified +2026-08-03 against each PR's file list and the `error.rs` at its head: +`#3417`, `#3549`, `#3992`, `#4186`, `#4191`, `#4194`, `#4195`, `#4243`. -Two more carry a code they did not allocate, inherited from the PR they are +Four entries this list used to carry have been removed, each for a different +reason, so they are not silently re-added: + +| Was listed | Why it is gone | +| --- | --- | +| `#4240` | Its head touches no file under `rs-platform-wallet-ffi` at all | +| `#4251` | Same — no file under this crate | +| `#4258` | Merged into `v4.2-dev` on 2026-08-03 (`ce8233edb7`); it claimed no code, so the merged table is unchanged | +| `#4264` | Closed. Its `error.rs` change (mapping new wallet errors onto the existing `ErrorInvalidParameter`) is carried by `#4243`, which is still open and is listed above | + +`#4243` is worth naming explicitly: it *does* modify `error.rs`, but only to map +new wallet errors onto the **existing** `ErrorInvalidParameter`. Touching +`error.rs` is not the same as claiming an integer, and this list tracks the +latter. + +Two more PRs carry a code they did not allocate, inherited from the PR they are stacked on rather than claimed fresh — they must not be read as a second claim on the number: @@ -113,34 +147,42 @@ on the number: | ---: | --- | --- | --- | | 31 | `ErrorSigningKeyUnavailable` | #4204, #4259 | #4183 | -#4196 also claims no new integer: it adds a token-less +PR `#4196` also claims no new integer: it adds a token-less `PlatformWalletError::StaleReservation` variant and deliberately routes it through the **existing** `ErrorStaleReservationToken`, so it allocates nothing and only has to follow that code's number (see below). -### Non-conforming allocations (rebase required) +### Non-conforming allocations (withdraw and reissue) These branches allocate into the same range from a stale base. They are listed here rather than in the proposed table because their numbers cannot stand as written — each row is a claim to be **withdrawn and reissued**, not an allocation of record. +A rebase is a precondition, not the remedy. `#3968`'s head does contain the +2026-08-01 base `ed4116b26c` (merge commit `debf67bdae` brought it in), so it is +not simply an un-rebased branch; it is behind the *current* base `5d68612a45`, +which is where #4268's merged `ErrorShutdownIncomplete = 27` lives. Rebasing +picks that up, but rebasing alone will not resolve anything below, because git +sees no conflict in any of it — the branch has to **edit its own enum**. + | Code | Name | Owning PR | Conflict | | ---: | --- | --- | --- | | 26 | `ErrorPersisterTransient` | #3968 | Contradicts **merged ABI** — 26 is `ErrorTransactionBroadcastRejected` | | 27 | `ErrorPersisterFatal` | #3968 | Contradicts **merged ABI** — 27 is #4268's `ErrorShutdownIncomplete` (was a #4185 collision until 2026-08-02) | | 28 | `ErrorTransactionBroadcastRejected` | #3968 | **Renumbers a shipped code** 26 → 28 — forbidden by rule 3 | -#3954's `ErrorShutdownIncomplete = 27` used to sit in this table. It is gone -because that claim **won**: #3954 was closed and superseded by **#4268**, which -merged 27 into `v4.2-dev` on 2026-08-02. See the collision history below. +PR `#3954`'s `ErrorShutdownIncomplete = 27` used to sit in this table. It is +gone because that claim **won**: #3954 was closed and superseded by **#4268**, +which merged 27 into `v4.2-dev` on 2026-08-02. See the collision history below. -#3968 is the serious one: rule 3 forbids renumbering a code that has shipped, -and `ErrorTransactionBroadcastRejected = 26` is merged ABI. Moving it to 28 -would silently reinterpret every 26 an already-compiled host returns. #3968 must -keep 26 where it is and take fresh integers from the frontier (37+) for its two -persister codes. Its 27 is now doubly wrong: 27 is merged ABI -(`ErrorShutdownIncomplete`), so rule 3 protects it too. +PR `#3968` is the serious one: rule 3 forbids renumbering a code that has +shipped, and `ErrorTransactionBroadcastRejected = 26` is merged ABI. Moving it +to 28 would silently reinterpret every 26 an already-compiled host returns. +PR #3968 must keep 26 where it is and take fresh integers **from the frontier +(38+)** for its two persister codes. Its 27 is now doubly wrong: 27 is merged +ABI (`ErrorShutdownIncomplete`), so rule 3 protects it too. Note that 28 is +reserved, not free — it is not available to #3968 either. ## Contested and pending @@ -169,10 +211,21 @@ failure this file's preamble describes, and it landed on the shielded-invite claim-recovery path (the error is raised from four sites in `wallet/shielded/operations.rs`, three of them inside the recovery function). -Fixed on #4204 together with the renumber: typed +**Partially** fixed on #4204 together with the renumber. Landed at head +`d78b940a03`: the typed Kotlin `PlatformWallet.ShieldedInviteAlreadyClaimed` (terminal, `isRetryable = false`), -the Swift case and its `init(ffi:)` arm, and a `DashSdkErrorTest` assertion that -pins 37 so a future move off the frontier fails the suite instead of the hosts. +the Swift `PlatformWalletResultCode.errorShieldedInviteAlreadyClaimed = 37` raw +case with its `init(ffi:)` arm, and a `DashSdkErrorTest` assertion that pins 37 +so a future move off the frontier fails the suite instead of the hosts. + +**Still missing on #4204, and it does not compile without it:** Swift's +`PlatformWalletError` has no `.shieldedInviteAlreadyClaimed` case, and its +`init(result:)` switches exhaustively over `PlatformWalletResultCode` with no +`default:`. Adding the raw case without the matching `init(result:)` arm makes +that switch non-exhaustive, so the Swift package fails to build at +`d78b940a03`. Rule 5's Swift clause is therefore not yet satisfied — treat the +Swift mirror as incomplete until #4204 adds the typed error case and its +conversion arm. **Lesson for rule 2:** the violation entered on a *review-round* commit, well after the PR's numbering had been reviewed and recorded as settled. Re-check @@ -186,8 +239,8 @@ to 30.** **#4184's 29 is settled and has not moved.** #4185's third code moved to 30 to clear it, and then — with the rest of the trio — to **36** when #4268 merged 27 -(see the collision history above). 30 is vacated (reserved, not reissuable) as a result. Nothing about -this section's resolution changed: 29 is #4184's. +(see the collision history above), which is why 30 is reserved rather than +free. Nothing about this section's resolution changed: 29 is #4184's. Note that neither #4184 nor #4256 was ever blocked by CI on this. Both are MERGEABLE with green checks, because two branches assigning the same @@ -197,36 +250,36 @@ That is the whole reason this file exists. **Still outstanding:** #4196 (see below). -### 30 — vacated (reserved, not reissuable); the old "consent code" reservation was stale +### 30 — vacated, then RESERVED (not free) `ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in -in-tree comments on #4183, #4204, and #4247/#4256's numbering rationale. It is +in-tree comments on #4204 and on #4247/#4256's numbering rationale. It is **not defined anywhere** — #4184, the PR that would have introduced it, does not contain it after a re-scope. Verified 2026-08-01 by reading `packages/rs-platform-wallet-ffi/src/error.rs` at the head of **every one of the 62 open PRs**: no PR anywhere defines a code 30. -30 was therefore genuinely free, and #4185 took it — then vacated it again on -2026-08-02 when the trio moved to 34–36. **30 is free once more, and is -deliberately not being reissued** (see the collision history above). The stale -"reserved for the consent code" comments should be dropped by whichever PR -touches them next. - -#4256 has done so on its own branch: its `ErrorTransactionSigning` numbering -rationale no longer describes 30 as reserved for the consent code. As of -`8febac177c` that rationale names #4268 as the owner of 27 and records where the -trio went. The equivalent stale comments on #4183 and #4204 are still there. - -#4184 has a smaller drift of the same kind, left in place because that branch is -settled and the drift is comment-only. Its reservation note reads "Codes 27-28 -are reserved" but then names **three** codes — `ErrorStaleReservationToken` / -`ErrorReservationTokenConsumed` / `ErrorReservationWalletMismatch`. That was -correct when the trio was 27/28/29 and #4184 was avoiding the range. It is now -doubly stale: the trio is at **34-36**, and 27 belongs to #4268's merged -`ErrorShutdownIncomplete`. The note should simply say that 29 sits below the -trio's 34-36 block. The discriminant itself -(`ErrorAssetLockInsufficientFunds = 29`) is correct and is the resolution of -record — only the prose is stale, and #4184 need not move. +30 was therefore genuinely free at that moment, and #4185 took it — then vacated +it again on 2026-08-02 when the trio moved to 34–36. Vacating is not the same as +freeing: **30 is now RESERVED and must not be reissued** (see the collision +history below for why). The stale "reserved for the consent code" comments +should be dropped by whichever PR touches them next. + +Three branches have now done so: + +* **#4256** — as of `8febac177c` its `ErrorTransactionSigning` rationale names + #4268 as the owner of 27 and records where the trio went. +* **#4183** — its enum comment no longer describes 27–28 as reserved for the + trio; on the 2026-08-03 rebase it was rewritten to say 28 and 30 are reserved + and 29 belongs to #4184, and to point here. +* **#4184** — same rebase, same correction. Its note used to read "Codes 27-28 + are reserved" while naming **three** codes, which was correct only while the + trio sat at 27/28/29. It now says 28 is skipped, 28 and 30 are reserved, and + the trio is at 34–36. The discriminant itself + (`ErrorAssetLockInsufficientFunds = 29`) never moved and remains the + resolution of record. + +The equivalent stale comment on **#4204** is still there. ### 27 / 28 — #3968 still collides; #3954's claim merged as #4268 @@ -234,7 +287,7 @@ Found by the same 2026-08-01 sweep. These now have rows — see **Non-conforming allocations** above for #3968 and #3954, and the inherited-code table for #4259. The detail behind those rows: -- **#3968** (`5931df745a`) numbers `ErrorPersisterTransient = 26`, +* **#3968** (`5931df745a`) numbers `ErrorPersisterTransient = 26`, `ErrorPersisterFatal = 27`, `ErrorTransactionBroadcastRejected = 28`. It branched before `26 = ErrorTransactionBroadcastRejected` merged, so it both contradicts merged ABI at 26 **and** collides with #4185 at 27 and 28. @@ -247,29 +300,29 @@ The detail behind those rows: a transient persister failure. Nothing in either branch's diff shows the contradiction. #3968 must leave 26 alone and take fresh integers for both persister codes. -- **#3954** (`93d0bd49b7`) numbered `ErrorShutdownIncomplete = 27`. This file +* **#3954** (`93d0bd49b7`) numbered `ErrorShutdownIncomplete = 27`. This file previously called that a proposed-vs-proposed collision and said #4185's older claim should stand. **That was wrong, and it resolved the other way.** #3954 was closed; its work landed as **#4268**, which merged 27 into `v4.2-dev` on 2026-08-02. #4185 and #4256 moved their trio to 34–36 in response. Merging decides an ABI number; being the older open claim does not. -- **#4259** (`4270d827c2`) carries `ErrorSigningKeyUnavailable = 31` — the same +* **#4259** (`9336bdbb71`) carries `ErrorSigningKeyUnavailable = 31` — the same number and name as #4183, i.e. inherited rather than a new allocation, like #4204. No conflict; recorded so the number is not double-counted. -#3968 needs a rebase onto current `v4.2-dev` and fresh integers from the -frontier (**37+**). It must leave 26 alone, and 27 is no longer available to it -either — that is merged ABI now. +PR `#3968` needs a rebase onto current `v4.2-dev` **and** fresh integers from +the frontier (**38+**). It must leave 26 alone; 27 is no longer available to it +either (merged ABI now), and neither are the reserved 28 and 30. ### 26 — #4196's trio collides with merged ABI (and is now two moves behind) -#4196 (stacked on #4185) branched before `26 = ErrorTransactionBroadcastRejected` +PR #4196 (stacked on #4185) branched before `26 = ErrorTransactionBroadcastRejected` merged, and its head still numbers the reservation trio **26 / 27 / 28**. It is now two moves behind: merging it as it stands would give 26 two meanings, give 27 two meanings against #4268's merged `ErrorShutdownIncomplete`, and contradict -#4185's own **34 / 35 / 36** for the same three names. #4196 needs a rebase and -must adopt whatever numbering #4185 lands with. No new integers are needed for -it. +the #4185 numbering of **34 / 35 / 36** for the same three names. It needs a +rebase and must adopt whatever numbering #4185 lands with. No new integers are +needed for it. **All three of those numbers come from the copy of #4185 that #4196 carries, not from #4196's own commits.** Restacking onto #4185's head therefore fixes the @@ -279,22 +332,22 @@ matching Kotlin KDoc both cite `ErrorStaleReservationToken` as **26**, and that becomes **34** post-restack. So the number #4196 must chase is 34. **The restack is not mechanical — it is blocked on a redesign.** Rebasing -#4196's three own commits (`2d29451d06`, `c64af1a6eb`, `ea4f783490`) onto -#4185's head (`6c37e8679e` when this was measured; now `3dec774929`) conflicts +the three commits #4196 owns (`2d29451d06`, `c64af1a6eb`, `ea4f783490`) onto +the #4185 head (`6c37e8679e` when this was measured; now `8813e98533`) conflicts in three files (10 hunks): `error.rs` (3), `wallet/core/broadcast.rs` (1), `wallet/signed_payment_registry.rs` (6). The `error.rs` hunks are genuinely mechanical. The other two are not, because #4185 redesigned the registry underneath #4196 after it branched: -- `registered_height` changed from `Option` to a mandatory `u32`. #4196's +* `registered_height` changed from `Option` to a mandatory `u32`. #4196's age guard is built around the `None` case meaning "guard disabled"; that case no longer exists. -- #4185 added a `SignedPaymentError::WalletRemoved` variant and an +* #4185 added a `SignedPaymentError::WalletRemoved` variant and an owner-stamped `funding_reservation_token` field. #4196 predates both. -- #4196 wants to *move* `RESERVATION_MAX_AGE_BLOCKS` and `reservation_expired` +* #4196 wants to *move* `RESERVATION_MAX_AGE_BLOCKS` and `reservation_expired` into `wallet/reservations.rs` so the V2 handle path can share them. #4185 has since rewritten both in place, with new generation-binding rationale. -- #4196's V2 guard documents "leave the stale reservation for the TTL rather +* #4196's V2 guard documents "leave the stale reservation for the TTL rather than release by outpoint". #4185 now releases by owner-guarded *token*, which changes that rationale rather than conflicting with it textually. @@ -315,7 +368,7 @@ key, restored from a typed signer completion code — whereas #4256's `BuilderError::SigningFailed` also covers unresolved derivation paths, sighash failures, and malformed signature encodings. Both codes are currently allocated. Maintainers may still choose to collapse them; that decision belongs to #4183 and -#4256 jointly and should be recorded here. +to #4256 jointly and should be recorded here. ## Collision history — the 27 / 28 / 30 → 34 / 35 / 36 move @@ -329,9 +382,9 @@ because the reason it kept moving is the failure mode this file exists to catch. | **2026-08-02** | **34 / 35 / 36** | **#4268 merged `ErrorShutdownIncomplete = 27` into the `v4.2-dev` ABI** | The third move is the instructive one. On 2026-08-01 this file recorded -#3954's `ErrorShutdownIncomplete = 27` as a *non-conforming* claim that had to -be withdrawn, on the reasoning that #4185's 27 was the older claim and should -stand. That reasoning was wrong in the only way that matters: seniority among +the `ErrorShutdownIncomplete = 27` of #3954 as a *non-conforming* claim that +had to be withdrawn, on the reasoning that #4185's 27 was the older claim and +should stand. That reasoning was wrong in the only way that matters: seniority among open PRs does not decide an ABI number — **merging does**. #3954 was closed and its work landed as #4268, which merged 27 first. An unmerged claim, however old, has no standing against merged ABI (rule 3, read from the other side). @@ -348,9 +401,10 @@ anything** — merged or proposed — rather than into the next free gap: Taking 34–36 rather than back-filling the vacated 28 and 30 costs two integers in a space that is nowhere near exhausted, and buys two things: the trio reads as one contiguous family, and it cannot be hit again by anything currently in -flight. **28 and 30 stay free.** Do not reissue them in this review cycle — a -reviewer who saw the earlier numbering would otherwise find a familiar number -attached to an unfamiliar meaning. +flight. **28 and 30 are therefore RESERVED, not free.** Do not reissue them in +this review cycle — a reviewer who saw the earlier numbering would otherwise +find a familiar number attached to an unfamiliar meaning. Rule 1 only permits +reusing a gap this file marks free, and this file marks neither of them free. The move landed on both branches on 2026-08-02: **#4185** (`3dec774929`) and **#4256** (`8febac177c`), each across the Rust enum discriminants and every @@ -363,8 +417,9 @@ cbindgen `PLATFORM_WALLET_FFI_RESULT_CODE_*` constants — so only the enum's ra values carried a number there. Neither branch's CI could have caught the collision, for the reason given at the -top of this file: a duplicate discriminant across two branches produces no -textual conflict. Both were MERGEABLE and green throughout. +top of this file: a duplicate integer across two branches produces no textual +conflict, and neither branch's tree contains both variants, so neither +compiler ever sees the E0081. Both were MERGEABLE and green throughout. ### Known mirror gap on #4256 (not a numbering issue) @@ -385,32 +440,55 @@ the same thing in both enums. ## Survey provenance -Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c`, and **re-verified -2026-08-02 against `v4.2-dev` at `5d68612a45`**, which is where -`ErrorShutdownIncomplete = 27` (#4268, `429667e723`) entered the merged table. -The 2026-08-02 pass re-read the added discriminants at the head of every open PR -that touches `error.rs`, `DashSdkError.kt` or `PlatformWalletResult.swift` -(#3968, #4183, #4184, #4185, #4186, #4191, #4194, #4195, #4196, #4204, #4243, -#4247, #4256, #4259) and confirmed the only claims in the 27–36 range are the -ones tabled above — in particular that 32 and 33 were **already taken** by -#4247/#4256, which is why the trio went to 34–36 rather than 32–34. - -PR heads of record: #3954 `93d0bd49b7` (closed), #3968 `5931df745a`, #4183 -`2cd948331b`, #4184 `bd19a3e020`, **#4185 `3dec774929`** (post-34/35/36 move), -#4186 `6f7abbadc1`, #4191 `8acb0bd14c`, #4194 `9efc0b7e3a`, #4195 `4f2eb06d64`, -#4196 `ea4f783490`, #4204 `7bc8a845c6`, #4240 `9328609a16`, #4247 `0dcdc743e7`, -#4251 `176f8ed3eb`, **#4256 `8febac177c`** (post-34/35/36 move), #4258 -`5adfc40032`, #4259 `4270d827c2`. Rows describing open PRs reflect those heads -and go stale as the PRs are updated; the merged table does not. - -Four of these were corrected on 2026-08-01 after the heads moved. The -`#4185 0b0d5c76d6 (post-renumber)` this list previously carried was wrong twice -over: `0b0d5c76d6` is the *parent* of the renumber commit `d854debb`, so it was -pre-renumber, and the branch has since advanced to `6c37e8679e`. #4184 was -recorded at `a9e418af50` (now `bd19a3e020`), #4247 at `72c000dcfd` (now -`0dcdc743e7`), and #4256 at `d8943ccf10` (now `9481e5783b`, which carries the -29 → 30 move). - -The 26 / 27 / 28 / 31 claims attributed to #3968, #3954 and #4259 were -re-verified on 2026-08-01 by reading `error.rs` at each of those three heads -directly, not from this file. +Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c`, re-verified 2026-08-02 +against `v4.2-dev` at `5d68612a45` (where `ErrorShutdownIncomplete = 27`, +PR #4268 `429667e723`, entered the merged table), and **re-verified again +2026-08-03 against the same base `5d68612a45`**, which is still `v4.2-dev`'s +head. + +The 2026-08-03 pass re-read the added discriminants directly at the *current* +head of every open PR that touches `error.rs`, `DashSdkError.kt` or +`PlatformWalletResult.swift`, and separately checked each PR's file list to +decide whether it belongs in the no-new-code inventory above. It confirmed: + +* 32 and 33 are still #4247/#4256's, which is why the trio sits at 34–36; +* 37 is #4204's post-renumber `ErrorShieldedInviteAlreadyClaimed`, mirrored in + Kotlin and half-mirrored in Swift (see the code-32 section); +* nothing in flight has taken 28, 30, or 38; +* #4247's head now also carries the 34/35/36 trio, inherited from #4185 (which + it is stacked on) rather than claimed a second time. + +PR heads of record, all read on 2026-08-03: + +| PR | Head | Note | +| --- | --- | --- | +| #3954 | `93d0bd49b7` | Closed; superseded by #4268 | +| #3968 | `5931df745a` | Contains base `ed4116b26c` but **not** `5d68612a45` | +| #4183 | `8387858016` | Rebased onto `5d68612a45` on 2026-08-03; keeps 31 | +| #4184 | `5bdae75391` | Rebased onto `5d68612a45` on 2026-08-03; keeps 29 | +| #4185 | `8813e98533` | Post-34/35/36 move | +| #4186 | `951260520c` | | +| #4191 | `8acb0bd14c` | Touches only `dashpay.rs` in this crate | +| #4194 | `1d812c7297` | | +| #4195 | `c471dc9fe6` | | +| #4196 | `ea4f783490` | Still 26/27/28; restack blocked, see above | +| #4204 | `d78b940a03` | Post-renumber 32 → 37; pre-#4268 base | +| #4240 | `3c19977a5a` | No file under this crate | +| #4243 | `f4be5b32f0` | Modifies `error.rs`, claims no integer | +| #4247 | `540def16a0` | Carries #4185's trio | +| #4251 | `176f8ed3eb` | No file under this crate | +| #4256 | `a456664278` | Post-34/35/36 move | +| #4258 | `ce8233edb7` | **Merged** 2026-08-03; claimed no code | +| #4259 | `9336bdbb71` | Carries #4183's 31 | +| #4264 | `bf88c92b85` | Closed; work carried by #4243 | + +Rows describing open PRs reflect those heads and go stale as the PRs are +updated; the merged table does not. + +That churn is the point of dating the table. An earlier revision of this list +carried `#4185 0b0d5c76d6 (post-renumber)`, which was wrong twice over: +`0b0d5c76d6` is the *parent* of the renumber commit `d854debb`, so it was +pre-renumber, and the branch had already moved on. Every head above was read +from GitHub on the date given, not copied forward from a previous revision of +this file, and the claims attributed to #3968, #3954, #4204 and #4259 were +confirmed by reading `error.rs` at each of those heads directly. From 3785d12e1041583332a3f1ef43053183b767d421 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Mon, 3 Aug 2026 19:40:12 -0400 Subject: [PATCH 08/22] docs(ffi): #4196 has restacked; spell out Swift's three mirror sites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three more live review findings, all verified against current PR heads. Rule 5 named a `PlatformWalletResultCode.init(result:)` that does not exist — `init(result:)` belongs to the downstream `PlatformWalletError`. As written, a contributor could add the Swift raw case and the typed error handling and still omit `PlatformWalletResultCode.init(ffi:)`, which is where the generated C constant is recognised; that switch has a `default:` yielding `.errorUnknown`, so the omission compiles and silently loses the code's identity before typed handling sees it. Rule 5 now enumerates all three Swift sites and says how each one fails: (1) the raw case, (2) the `init(ffi:)` arm — silent, and (3) `PlatformWalletError` + its `init(result:)` arm — a hard compile error, since that switch is exhaustive with no `default:`. That third failure is exactly what #4204 is sitting on at `d78b940a03`. #4196 is no longer blocked. Its head moved to `12492e8c54`, the restack onto #4185 is done, #4185's head `8813e98533` is an ancestor, the trio reads 34/35/36, and the PR is MERGEABLE against v4.2-dev. Verified the numeric references it owns were carried too: the `StaleReservationToken` KDoc and `fromPlatformWalletNative` mapping in `DashSdkError.kt` both read 34, and the V2 broadcast KDoc in `ManagedCoreWallet.kt` reads 34 with the rest symbolic. `PlatformWalletError::StaleReservation` refers to the code symbolically and never carried a number. The section is now a resolution rather than an open item; the account of why the restack was hard is kept, since that was the substance of the delay. The code-30 sweep was overstated. "No PR anywhere defines a code 30" is false for the surveyed heads — #4185 and #4256 both did; that was the allocation, not a competing claim. It now reads "no PR unrelated to #4185 defines a code 30", which is the claim that actually supports the conclusion. The list of branches carrying the stale consent-code reservation is corrected to #4183, #4204 and #4256's pre-renumber rationale (#4247 was never one of them). Provenance and the proposed table pick up #4196's new head. markdownlint MD018/MD004 remain at 0. --- .../ERROR_CODE_REGISTRY.md | 141 ++++++++++-------- 1 file changed, 79 insertions(+), 62 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index b30490b8232..0e1d504be9a 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -45,13 +45,22 @@ branch's diff. that are still only proposed (unmerged) may be renumbered to resolve a collision; codes on `v4.2-dev` may not. 4. **Do not reuse a retired integer.** Mark it reserved and move on. -5. **Update the mirrors in the same PR**: the Rust enum, the Swift - `PlatformWalletResultCode` + its `init(result:)` switch, and — where the code - deserves typed handling — the Kotlin `fromPlatformWalletNative` mapping and - `DashSdkErrorTest`. Kotlin is allowed to be non-exhaustive: unmapped codes - fall through to `PlatformWallet.Generic(code, …)`, which preserves the - integer. Swift is exhaustive; an unmirrored code surfaces as - `.errorUnknown` there and loses its identity. +5. **Update the mirrors in the same PR.** Swift needs **three** edits, not one, + and they fail in different ways: + 1. `PlatformWalletResultCode` — the raw case. + 2. `PlatformWalletResultCode.init(ffi:)` — the arm mapping the generated C + constant. This switch has a `default:` that yields `.errorUnknown`, so + omitting the arm compiles fine and silently loses the code's identity + *before* any typed handling sees it. + 3. `PlatformWalletError` — the typed case, **and** its `init(result:)` arm. + That switch is exhaustive with no `default:`, so adding a raw case in (1) + without the matching arm here makes it non-exhaustive and the Swift + package stops compiling. + + Then, where the code deserves typed handling, the Kotlin + `fromPlatformWalletNative` mapping and `DashSdkErrorTest`. Kotlin is allowed + to be non-exhaustive: unmapped codes fall through to + `PlatformWallet.Generic(code, …)`, which preserves the integer. 6. **Blocks 98–99 are terminal sentinels** (`NotFound`, `ErrorUnknown`) and are not an allocation frontier. New codes go after the highest allocated value below them. @@ -115,7 +124,7 @@ this file. | 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204, #4259) | | 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | | 33 | `ErrorTransactionSigning` | #4256 | In review | -| 34 | `ErrorStaleReservationToken` | #4185 | In review — **moved 27 → 34** (also carried by #4256; #4196 inherits on restack) | +| 34 | `ErrorStaleReservationToken` | #4185 | In review — **moved 27 → 34** (also carried by #4256 and, post-restack, #4196) | | 35 | `ErrorReservationTokenConsumed` | #4185 | In review — **moved 28 → 35** (also carried by #4256) | | 36 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 30 → 36** (also carried by #4256) | | 37 | `ErrorShieldedInviteAlreadyClaimed` | #4204 | In review — **moved 32 → 37** (collided with #4247's `ErrorTransactionBuild`; see below) | @@ -150,7 +159,8 @@ on the number: PR `#4196` also claims no new integer: it adds a token-less `PlatformWalletError::StaleReservation` variant and deliberately routes it through the **existing** `ErrorStaleReservationToken`, so it allocates nothing -and only has to follow that code's number (see below). +and only has to follow that code's number. As of 2026-08-03 it has restacked +onto #4185 and follows 34 (see below). ### Non-conforming allocations (withdraw and reissue) @@ -253,17 +263,22 @@ That is the whole reason this file exists. ### 30 — vacated, then RESERVED (not free) `ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in -in-tree comments on #4204 and on #4247/#4256's numbering rationale. It is -**not defined anywhere** — #4184, the PR that would have introduced it, does not -contain it after a re-scope. +in-tree comments on #4183 and #4204, and in #4256's pre-renumber numbering +rationale. It is **not defined anywhere** — #4184, the PR that would have +introduced it, does not contain it after a re-scope. Verified 2026-08-01 by reading `packages/rs-platform-wallet-ffi/src/error.rs` at -the head of **every one of the 62 open PRs**: no PR anywhere defines a code 30. -30 was therefore genuinely free at that moment, and #4185 took it — then vacated -it again on 2026-08-02 when the trio moved to 34–36. Vacating is not the same as -freeing: **30 is now RESERVED and must not be reissued** (see the collision -history below for why). The stale "reserved for the consent code" comments -should be dropped by whichever PR touches them next. +the head of **every one of the 62 open PRs**. Stated precisely, because the +unqualified version of this sentence is false: **no PR unrelated to #4185 +defines a code 30.** #4185 itself, and #4256 downstream of it, did define +`ErrorReservationWalletMismatch = 30` at their surveyed heads — that was the +allocation, not a competing claim. So nothing contested 30, #4185's claim stood, +and the stale consent-code reservation never conflicted with it. + +PR #4185 then vacated 30 on 2026-08-02 when the trio moved to 34–36. Vacating +is not the same as freeing: **30 is now RESERVED and must not be reissued** (see +the collision history below for why). The stale "reserved for the consent code" +comments should be dropped by whichever PR touches them next. Three branches have now done so: @@ -314,50 +329,51 @@ PR `#3968` needs a rebase onto current `v4.2-dev` **and** fresh integers from the frontier (**38+**). It must leave 26 alone; 27 is no longer available to it either (merged ABI now), and neither are the reserved 28 and 30. -### 26 — #4196's trio collides with merged ABI (and is now two moves behind) - -PR #4196 (stacked on #4185) branched before `26 = ErrorTransactionBroadcastRejected` -merged, and its head still numbers the reservation trio **26 / 27 / 28**. It is -now two moves behind: merging it as it stands would give 26 two meanings, give 27 -two meanings against #4268's merged `ErrorShutdownIncomplete`, and contradict -the #4185 numbering of **34 / 35 / 36** for the same three names. It needs a -rebase and must adopt whatever numbering #4185 lands with. No new integers are -needed for it. - -**All three of those numbers come from the copy of #4185 that #4196 carries, not -from #4196's own commits.** Restacking onto #4185's head therefore fixes the -trio for free — including the two moves #4196 never had to make itself. The one -number #4196 does own is a doc reference: its `StaleReservation` variant and the -matching Kotlin KDoc both cite `ErrorStaleReservationToken` as **26**, and that -becomes **34** post-restack. So the number #4196 must chase is 34. - -**The restack is not mechanical — it is blocked on a redesign.** Rebasing -the three commits #4196 owns (`2d29451d06`, `c64af1a6eb`, `ea4f783490`) onto -the #4185 head (`6c37e8679e` when this was measured; now `8813e98533`) conflicts -in three files (10 hunks): `error.rs` (3), -`wallet/core/broadcast.rs` (1), `wallet/signed_payment_registry.rs` (6). The -`error.rs` hunks are genuinely mechanical. The other two are not, because #4185 -redesigned the registry underneath #4196 after it branched: - -* `registered_height` changed from `Option` to a mandatory `u32`. #4196's - age guard is built around the `None` case meaning "guard disabled"; that case - no longer exists. +### 26 — RESOLVED: #4196 restacked onto #4185 and is on 34 / 35 / 36 + +**Closed out 2026-08-03.** PR #4196 (stacked on #4185) branched before +`26 = ErrorTransactionBroadcastRejected` merged, and for most of this file's +life its head still numbered the reservation trio **26 / 27 / 28** — two moves +behind, in a state where merging it would have given 26 two meanings, given 27 +two meanings against #4268's merged `ErrorShutdownIncomplete`, and contradicted +the **34 / 35 / 36** of #4185 for the same three names. + +That is no longer the case. At head `12492e8c54` the restack is done: +`ErrorStaleReservationToken = 34`, `ErrorReservationTokenConsumed = 35`, +`ErrorReservationWalletMismatch = 36`, `ErrorShutdownIncomplete = 27` present +from the merged base, #4185's head `8813e98533` is an ancestor, and the PR is +MERGEABLE against `v4.2-dev`. It still allocates no integer of its own. + +The numeric references #4196 owns were carried along with it. Verified at +`12492e8c54`: + +* `DashSdkError.kt` — the `StaleReservationToken` KDoc reads "native code 34", + and `fromPlatformWalletNative` maps `34 -> PlatformWallet.StaleReservationToken`. +* `ManagedCoreWallet.kt` — its V2 broadcast KDoc reads "native code 34, shared + with the deferred-token surface"; the remaining mentions are symbolic + `[StaleReservationToken]` links carrying no number. +* `PlatformWalletError::StaleReservation` — refers to the FFI code symbolically + and has never contained a number, so it needed no update. + +**Kept for the record, because the delay was the interesting part.** The restack +was not mechanical. Rebasing the three commits #4196 owned onto #4185's head +conflicted in three files (10 hunks): `error.rs` (3), +`wallet/core/broadcast.rs` (1), `wallet/signed_payment_registry.rs` (6). Only +the `error.rs` hunks were mechanical, because #4185 had redesigned the registry +underneath #4196 after it branched: + +* `registered_height` changed from `Option` to a mandatory `u32`, and + #4196's age guard was built around the `None` case meaning "guard disabled". * #4185 added a `SignedPaymentError::WalletRemoved` variant and an - owner-stamped `funding_reservation_token` field. #4196 predates both. -* #4196 wants to *move* `RESERVATION_MAX_AGE_BLOCKS` and `reservation_expired` - into `wallet/reservations.rs` so the V2 handle path can share them. #4185 has - since rewritten both in place, with new generation-binding rationale. -* #4196's V2 guard documents "leave the stale reservation for the TTL rather - than release by outpoint". #4185 now releases by owner-guarded *token*, which - changes that rationale rather than conflicting with it textually. - -Resolving this means re-deriving #4196's age guard against the new registry -shape, with real semantic decisions to make (does the V2 guard now release by -owner token? what replaces the `None`-disables-the-guard branch?). That is -author work, not conflict resolution, and it is why this was left rather than -forced through. shumkov's 07-24 request to restack onto #4185's post-renumber -head is actionable in the sense that the base now exists — but the restack -itself needs #4196's author. + owner-stamped `funding_reservation_token` field, both of which #4196 predated. +* #4196 wanted to *move* `RESERVATION_MAX_AGE_BLOCKS` and `reservation_expired` + into `wallet/reservations.rs`; #4185 had since rewritten both in place. +* #4196's V2 guard documented "leave the stale reservation for the TTL rather + than release by outpoint", while #4185 now releases by owner-guarded *token*. + +Re-deriving the age guard against the new registry shape was author work, not +conflict resolution — which is why this sat for as long as it did rather than +being forced through by whoever was maintaining this file. ### 31 vs 33 — two signing-related codes, deliberately distinct @@ -455,6 +471,7 @@ decide whether it belongs in the no-new-code inventory above. It confirmed: * 37 is #4204's post-renumber `ErrorShieldedInviteAlreadyClaimed`, mirrored in Kotlin and half-mirrored in Swift (see the code-32 section); * nothing in flight has taken 28, 30, or 38; +* #4196 has restacked onto #4185 and now carries 34/35/36 rather than 26/27/28; * #4247's head now also carries the 34/35/36 trio, inherited from #4185 (which it is stacked on) rather than claimed a second time. @@ -471,7 +488,7 @@ PR heads of record, all read on 2026-08-03: | #4191 | `8acb0bd14c` | Touches only `dashpay.rs` in this crate | | #4194 | `1d812c7297` | | | #4195 | `c471dc9fe6` | | -| #4196 | `ea4f783490` | Still 26/27/28; restack blocked, see above | +| #4196 | `12492e8c54` | **Restacked onto #4185 on 2026-08-03**; trio now 34/35/36, MERGEABLE | | #4204 | `d78b940a03` | Post-renumber 32 → 37; pre-#4268 base | | #4240 | `3c19977a5a` | No file under this crate | | #4243 | `f4be5b32f0` | Modifies `error.rs`, claims no integer | From 01b086073f6fe28eb99758fb946f682e8f073866 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 4 Aug 2026 07:53:50 -0400 Subject: [PATCH 09/22] docs(ffi): record 31 as merged ABI; sweep the stale open-PR state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-verified the whole document against the CURRENT `origin/v4.2-dev` (`97904ed2fc`), not the `f53e5eef0a` the review comment cited and not the `5d68612a45` this file was last compiled against. `ErrorSigningKeyUnavailable = 31` is merged ABI. It landed in `189a3abb1c` (#4183, stacked on #4191) together with its Rust C-facing discriminant and complete Swift and Kotlin mirrors — the raw case, the `init(ffi:)` arm, the typed `PlatformWalletError` case with its `init(result:)` arm, and Kotlin's `31 -> PlatformWallet.SigningKeyUnavailable`. Leaving it under "Proposed allocations", whose preamble explicitly permits renumbering, contradicted rule 3. Moved to the merged table. Four PRs merged into `v4.2-dev` on 2026-08-04 and this file still treated all four as open: #4191 (`0e2282b586`), #4183 (`189a3abb1c`), #4277 (`6704a41a85`), #4251 (`7afc8a8ff3`). Only #4183 claimed an integer; the other three claimed none, and #4277 is now recorded as the merged precedent for "touches error.rs but allocates nothing" (it routes TxMetadataPayloadTooLarge onto the existing ErrorInvalidParameter). Dependent sections updated so nothing implies 31 may still move: the frontier breakdown (unchanged at 38), the proposed table, the inherited-code table (31 is trunk now, not an inheritable claim), the collision-history bullet list, the no-new-code open-PR inventory, the 31-vs-33 note (collapsing 31 is no longer available; only #4256's 33 is still open), and the survey provenance plus the PR-heads-of-record table. Also refreshed, because a re-dated provenance section must not carry claims that are now false: #4204's and #4256's Swift mirror gaps are both closed, and the stale ErrorAssetLockCrossDomainConsentRequired comments are gone from every branch that carried them. Every discriminant, mirror, PR state, and SHA above was read from git or the GitHub API on 2026-08-04. The four merge SHAs were confirmed ancestors of `97904ed2fc`. Co-Authored-By: Claude Opus 4.8 --- .../ERROR_CODE_REGISTRY.md | 231 ++++++++++++------ 1 file changed, 152 insertions(+), 79 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 0e1d504be9a..f289cc4c59c 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -99,11 +99,12 @@ These are shipped ABI. Do not renumber. | 25 | `ErrorAssetLockFundingMismatch` | | | 26 | `ErrorTransactionBroadcastRejected` | Merged in `9302c62e8b`; took a number several open branches had been treating as free | | 27 | `ErrorShutdownIncomplete` | Merged 2026-08-02 by **#4268** (`429667e723`). A quiesce/drain barrier missed its budget. **Took the number #4185 had held since before this file existed** — see the collision history below | +| 31 | `ErrorSigningKeyUnavailable` | Merged 2026-08-04 by **#4183** (merge commit `189a3abb1c`, stacked on #4191). The signer holds no usable private key for a requested public key. Landed complete in that one commit: the Rust C-facing discriminant, Swift's `errorSigningKeyUnavailable = 31` raw case *and* its `init(ffi:)` arm *and* the typed `PlatformWalletError` case with its `init(result:)` arm, and Kotlin's `31 -> PlatformWallet.SigningKeyUnavailable`. Rule 3 now protects it — see the 31-vs-33 note below | | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next allocatable integer: 38** — 27–37 are all claimed (27 merged; 29 and -31–37 in the proposed table below; 28 and 30 reserved). **28 and 30 are +**Next allocatable integer: 38** — 27–37 are all claimed (27 and 31 merged; 29 +and 32–37 in the proposed table below; 28 and 30 reserved). **28 and 30 are RESERVED, not free**: #4185 and #4256 vacated them when the reservation trio moved to 34–36, but they are deliberately left unclaimed rather than back-filled, so that the trio stays contiguous and no number is reused within a @@ -121,7 +122,6 @@ this file. | 28 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 29 | `ErrorAssetLockInsufficientFunds` | #4184 | In review — **keeps 29** (collision resolved) | | 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | -| 31 | `ErrorSigningKeyUnavailable` | #4183 | In review (also carried by #4204, #4259) | | 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | | 33 | `ErrorTransactionSigning` | #4256 | In review | | 34 | `ErrorStaleReservationToken` | #4185 | In review — **moved 27 → 34** (also carried by #4256 and, post-restack, #4196) | @@ -129,38 +129,59 @@ this file. | 36 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 30 → 36** (also carried by #4256) | | 37 | `ErrorShieldedInviteAlreadyClaimed` | #4204 | In review — **moved 32 → 37** (collided with #4247's `ErrorTransactionBuild`; see below) | +**Code 31 left this table on 2026-08-04.** `ErrorSigningKeyUnavailable` sat here +as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged +table above and rule 3 applies to it in full. Nothing else in this table has +merged, and the frontier is unchanged at 38. + Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified -2026-08-03 against each PR's file list and the `error.rs` at its head: -`#3417`, `#3549`, `#3992`, `#4186`, `#4191`, `#4194`, `#4195`, `#4243`. +2026-08-04 against each PR's file list and the `error.rs` at its head: +`#3417`, `#3549`, `#3992`, `#4186`, `#4194`, `#4195`, `#4243`. -Four entries this list used to carry have been removed, each for a different +Five entries this list used to carry have been removed, each for a stated reason, so they are not silently re-added: | Was listed | Why it is gone | | --- | --- | -| `#4240` | Its head touches no file under `rs-platform-wallet-ffi` at all | -| `#4251` | Same — no file under this crate | +| `#4240` | Its head touches no file under `rs-platform-wallet-ffi` at all — still true at `a167afe84c` | +| `#4251` | Was listed as touching no file under this crate; **merged into `v4.2-dev` on 2026-08-04** (`7afc8a8ff3`) having touched none, so nothing here changes | | `#4258` | Merged into `v4.2-dev` on 2026-08-03 (`ce8233edb7`); it claimed no code, so the merged table is unchanged | | `#4264` | Closed. Its `error.rs` change (mapping new wallet errors onto the existing `ErrorInvalidParameter`) is carried by `#4243`, which is still open and is listed above | +| `#4191` | **Merged into `v4.2-dev` on 2026-08-04** (`0e2282b586`). In this crate it only ever touched `dashpay.rs`; it claimed no code, so the merged table gained nothing from it — though #4183, which was stacked on it, did | -`#4243` is worth naming explicitly: it *does* modify `error.rs`, but only to map +`#4186`, `#4194`, `#4195` and `#4243` are worth naming explicitly: each *does* +modify `error.rs`, but none of them adds a discriminant — `#4243`'s change maps new wallet errors onto the **existing** `ErrorInvalidParameter`. Touching `error.rs` is not the same as claiming an integer, and this list tracks the latter. -Two more PRs carry a code they did not allocate, inherited from the PR they are -stacked on rather than claimed fresh — they must not be read as a second claim -on the number: +**`#4277` is the merged precedent for that distinction.** It merged into +`v4.2-dev` on 2026-08-04 (`6704a41a85`) with a change to this crate's +`error.rs`, and it claimed no integer: it routes +`PlatformWalletError::TxMetadataPayloadTooLarge` onto the existing +`ErrorInvalidParameter`, with an in-line comment saying it does so deliberately +"so no new numeric code churns the Swift/Kotlin mirror enums". The merged table +is unchanged by it. + +The **inherited-code table** that used to sit here is gone, and its single row is +worth recording rather than deleting: | Code | Name | Carried by | Allocated to | | ---: | --- | --- | --- | | 31 | `ErrorSigningKeyUnavailable` | #4204, #4259 | #4183 | +#4183 merged on 2026-08-04, so 31 is no longer an allocation anyone can inherit +— it is trunk. Every branch that has rebased onto current `v4.2-dev` carries it +from the base, which is not a claim and cannot be double-counted. Verified +2026-08-04 at the heads of #4184, #4185, #4186, #4194, #4195, #4196, #4204, +#4240, #4247, #4256 and #4259: all eleven show `ErrorSigningKeyUnavailable = 31` +inherited from the merged base. + PR `#4196` also claims no new integer: it adds a token-less `PlatformWalletError::StaleReservation` variant and deliberately routes it through the **existing** `ErrorStaleReservationToken`, so it allocates nothing -and only has to follow that code's number. As of 2026-08-03 it has restacked -onto #4185 and follows 34 (see below). +and only has to follow that code's number. As of 2026-08-04 (head `9909f77546`) +it is restacked onto #4185 and follows 34 (see below). ### Non-conforming allocations (withdraw and reissue) @@ -171,9 +192,10 @@ allocation of record. A rebase is a precondition, not the remedy. `#3968`'s head does contain the 2026-08-01 base `ed4116b26c` (merge commit `debf67bdae` brought it in), so it is -not simply an un-rebased branch; it is behind the *current* base `5d68612a45`, -which is where #4268's merged `ErrorShutdownIncomplete = 27` lives. Rebasing -picks that up, but rebasing alone will not resolve anything below, because git +not simply an un-rebased branch; it is behind the *current* base `97904ed2fc`, +which is where both #4268's merged `ErrorShutdownIncomplete = 27` and #4183's +merged `ErrorSigningKeyUnavailable = 31` live. Rebasing +picks those up, but rebasing alone will not resolve anything below, because git sees no conflict in any of it — the branch has to **edit its own enum**. | Code | Name | Owning PR | Conflict | @@ -221,21 +243,24 @@ failure this file's preamble describes, and it landed on the shielded-invite claim-recovery path (the error is raised from four sites in `wallet/shielded/operations.rs`, three of them inside the recovery function). -**Partially** fixed on #4204 together with the renumber. Landed at head +Fixed on #4204 together with the renumber. Landed at head `d78b940a03`: the typed Kotlin `PlatformWallet.ShieldedInviteAlreadyClaimed` (terminal, `isRetryable = false`), the Swift `PlatformWalletResultCode.errorShieldedInviteAlreadyClaimed = 37` raw case with its `init(ffi:)` arm, and a `DashSdkErrorTest` assertion that pins 37 so a future move off the frontier fails the suite instead of the hosts. -**Still missing on #4204, and it does not compile without it:** Swift's -`PlatformWalletError` has no `.shieldedInviteAlreadyClaimed` case, and its -`init(result:)` switches exhaustively over `PlatformWalletResultCode` with no -`default:`. Adding the raw case without the matching `init(result:)` arm makes -that switch non-exhaustive, so the Swift package fails to build at -`d78b940a03`. Rule 5's Swift clause is therefore not yet satisfied — treat the -Swift mirror as incomplete until #4204 adds the typed error case and its -conversion arm. +The Swift half of that fix was **incomplete at `d78b940a03`, and is complete +now.** At that head `PlatformWalletError` had no `.shieldedInviteAlreadyClaimed` +case even though `init(result:)` switches exhaustively over +`PlatformWalletResultCode` with no `default:` — adding the raw case without the +matching arm makes that switch non-exhaustive, so the Swift package did not +build. **Closed since.** Verified 2026-08-04 at #4204's current head +`4efecd5b71`: the raw case, its `init(ffi:)` arm, the typed +`PlatformWalletError.shieldedInviteAlreadyClaimed` case and its `init(result:)` +arm are all present. Rule 5's Swift clause is satisfied. Kept here because the +sequence is the lesson — one of rule 5's three Swift edits landed a full review +round after the other two. **Lesson for rule 2:** the violation entered on a *review-round* commit, well after the PR's numbering had been reviewed and recorded as settled. Re-check @@ -262,10 +287,12 @@ That is the whole reason this file exists. ### 30 — vacated, then RESERVED (not free) -`ErrorAssetLockCrossDomainConsentRequired` is named as the holder of 30 in +`ErrorAssetLockCrossDomainConsentRequired` was named as the holder of 30 in in-tree comments on #4183 and #4204, and in #4256's pre-renumber numbering rationale. It is **not defined anywhere** — #4184, the PR that would have -introduced it, does not contain it after a re-scope. +introduced it, does not contain it after a re-scope. Those comments are all gone +now: grepping `packages` at `v4.2-dev` `97904ed2fc` on 2026-08-04 returns no +occurrence of the name, and neither does #4204's head `4efecd5b71`. Verified 2026-08-01 by reading `packages/rs-platform-wallet-ffi/src/error.rs` at the head of **every one of the 62 open PRs**. Stated precisely, because the @@ -286,7 +313,10 @@ Three branches have now done so: #4268 as the owner of 27 and records where the trio went. * **#4183** — its enum comment no longer describes 27–28 as reserved for the trio; on the 2026-08-03 rebase it was rewritten to say 28 and 30 are reserved - and 29 belongs to #4184, and to point here. + and 29 belongs to #4184, and to point here. **#4183 merged on 2026-08-04**, so + that corrected comment is now the in-tree text at `v4.2-dev` — the reservation + of 28 and 30 and #4184's claim on 29 are recorded in `error.rs` itself, not + only here. * **#4184** — same rebase, same correction. Its note used to read "Codes 27-28 are reserved" while naming **three** codes, which was correct only while the trio sat at 27/28/29. It now says 28 is skipped, 28 and 30 are reserved, and @@ -294,7 +324,11 @@ Three branches have now done so: (`ErrorAssetLockInsufficientFunds = 29`) never moved and remains the resolution of record. -The equivalent stale comment on **#4204** is still there. +The equivalent stale comment on **#4204** is gone too. It was not fixed by hand: +#4204 rebased onto the merged base, and its `error.rs` at `4efecd5b71` now +carries #4183's corrected 28/29/30 note verbatim from trunk. All four branches +that ever held the stale reservation text — #4256, #4183, #4184, #4204 — are +clear, and #4183's version of the note is now trunk. ### 27 / 28 — #3968 still collides; #3954's claim merged as #4268 @@ -321,9 +355,11 @@ The detail behind those rows: was closed; its work landed as **#4268**, which merged 27 into `v4.2-dev` on 2026-08-02. #4185 and #4256 moved their trio to 34–36 in response. Merging decides an ABI number; being the older open claim does not. -* **#4259** (`9336bdbb71`) carries `ErrorSigningKeyUnavailable = 31` — the same - number and name as #4183, i.e. inherited rather than a new allocation, like - #4204. No conflict; recorded so the number is not double-counted. +* **#4259** carries `ErrorSigningKeyUnavailable = 31` — the same number and name + as #4183, i.e. inherited rather than a new allocation, like #4204. No + conflict; recorded so the number is not double-counted. This is now moot: + #4183 merged on 2026-08-04, so at #4259's current head `5b77dfd8f1` the 31 is + simply the merged base's, and there is no second claim to reconcile. PR `#3968` needs a rebase onto current `v4.2-dev` **and** fresh integers from the frontier (**38+**). It must leave 26 alone; 27 is no longer available to it @@ -382,9 +418,16 @@ took 33, on the grounds that 31 (`ErrorSigningKeyUnavailable`, #4183) asserts a specific contract — the signer holds no usable private key for a requested public key, restored from a typed signer completion code — whereas #4256's `BuilderError::SigningFailed` also covers unresolved derivation paths, sighash -failures, and malformed signature encodings. Both codes are currently allocated. -Maintainers may still choose to collapse them; that decision belongs to #4183 and -to #4256 jointly and should be recorded here. +failures, and malformed signature encodings. + +**That question is now half-settled by merging, not by agreement.** #4183 merged +on 2026-08-04, so **31 is ABI** and rule 3 forbids renumbering or retiring it; +it also ships with complete Swift and Kotlin mirrors, so hosts already +distinguish it. The only decision still open is #4256's: whether 33 stays a +separate code or `BuilderError::SigningFailed` is instead routed onto the +existing 31. That is #4256's alone to make now, and if it is made it should be +recorded here. What is no longer available is collapsing the pair *into* 33, or +moving 31 anywhere. ## Collision history — the 27 / 28 / 30 → 34 / 35 / 36 move @@ -410,10 +453,16 @@ anything** — merged or proposed — rather than into the next free gap: * 27 `ErrorShutdownIncomplete` (merged, #4268) * 29 `ErrorAssetLockInsufficientFunds` (#4184) -* 31 `ErrorSigningKeyUnavailable` (#4183/#4204/#4259) +* 31 `ErrorSigningKeyUnavailable` (**merged 2026-08-04, #4183**; was proposed when the trio jumped it) * 32 `ErrorTransactionBuild` (#4247/#4256) * 33 `ErrorTransactionSigning` (#4256) +Two of those five are now shipped ABI rather than proposals: 27 already was when +the trio moved, and 31 has merged since. That is the argument for the move made +retroactively — a number that looked merely "claimed by an open PR" on +2026-08-02 is unrenumberable ABI two days later, and anything sitting on it +would now be stuck there. + Taking 34–36 rather than back-filling the vacated 28 and 30 costs two integers in a space that is nowhere near exhausted, and buys two things: the trio reads as one contiguous family, and it cannot be hit again by anything currently in @@ -437,15 +486,23 @@ top of this file: a duplicate integer across two branches produces no textual conflict, and neither branch's tree contains both variants, so neither compiler ever sees the E0081. Both were MERGEABLE and green throughout. -### Known mirror gap on #4256 (not a numbering issue) +### Mirror gap on #4256 — CLOSED (was never a numbering issue) + +Noted while grepping the mirrors for this move: #4256 declared +`ErrorTransactionBuild = 32` and `ErrorTransactionSigning = 33` in Rust and +mapped both in Kotlin, but its Swift `PlatformWalletResultCode` declared +**neither** — no `case`, and no arm in `init(ffi:)`, so both fell into that +switch's `default:` and would have reached Swift hosts as `.errorUnknown`, +losing their identity. That is rule 5's Swift clause. It was left for #4256's +author rather than folded into the renumber, since it was a missing mirror and +not a wrong number. -Noted while grepping the mirrors for this move: #4256 declares -`ErrorTransactionBuild = 32` and `ErrorTransactionSigning = 33` in Rust and maps -both in Kotlin, but its Swift `PlatformWalletResultCode` declares **neither** — -no `case`, and no arm in `init(ffi:)`, so both fall into that switch's -`default:` and reach Swift hosts as `.errorUnknown`, losing their identity. That -is rule 5's Swift clause. Left for #4256's author rather than folded into the -renumber; it is a missing mirror, not a wrong number. +**Fixed.** Verified 2026-08-04 at #4256's head `862036b18d`: +`errorTransactionBuild = 32` and `errorTransactionSigning = 33` raw cases, both +`init(ffi:)` arms, the typed `PlatformWalletError.transactionBuild` / +`.transactionSigning` cases and their `init(result:)` arms are all present. Both +of this file's outstanding Swift mirror gaps — this one and #4204's — closed +between the 2026-08-03 and 2026-08-04 passes. ## Sibling FFI crates @@ -458,46 +515,62 @@ the same thing in both enums. Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c`, re-verified 2026-08-02 against `v4.2-dev` at `5d68612a45` (where `ErrorShutdownIncomplete = 27`, -PR #4268 `429667e723`, entered the merged table), and **re-verified again -2026-08-03 against the same base `5d68612a45`**, which is still `v4.2-dev`'s -head. - -The 2026-08-03 pass re-read the added discriminants directly at the *current* -head of every open PR that touches `error.rs`, `DashSdkError.kt` or -`PlatformWalletResult.swift`, and separately checked each PR's file list to -decide whether it belongs in the no-new-code inventory above. It confirmed: - -* 32 and 33 are still #4247/#4256's, which is why the trio sits at 34–36; -* 37 is #4204's post-renumber `ErrorShieldedInviteAlreadyClaimed`, mirrored in - Kotlin and half-mirrored in Swift (see the code-32 section); +PR #4268 `429667e723`, entered the merged table), re-verified 2026-08-03 against +that same base, and **re-verified again 2026-08-04 against `v4.2-dev` at +`97904ed2fc`**, which is the current head. + +The base moved on 2026-08-04, which is what made that pass necessary: four PRs +merged into `v4.2-dev` that day — **#4191** (`0e2282b586`), **#4183** +(`189a3abb1c`), **#4277** (`6704a41a85`) and **#4251** (`7afc8a8ff3`) — and one +of them, #4183, moved a number out of this file's proposed table and into the +ABI. Each of those four SHAs is the **merge commit on `v4.2-dev`**, confirmed by +`git merge-base --is-ancestor` against `97904ed2fc`, not a PR head SHA. + +The 2026-08-04 pass re-read the discriminants directly, in-tree and at the +*current* head of every open PR that touches `error.rs`, `DashSdkError.kt` or +`PlatformWalletResult.swift`, and separately re-checked each PR's file list. It +confirmed: + +* in-tree at `97904ed2fc`, `error.rs` runs 0–27 contiguously and then **31**, + with 28, 29, 30 and everything from 32 up absent. So 31 is the only number + this file had listed as proposed that is now merged, and the frontier is + unchanged at 38; +* `31 = ErrorSigningKeyUnavailable` has **complete** host mirrors on `v4.2-dev` + — Swift's raw case, its `init(ffi:)` arm, the typed `PlatformWalletError` case + and its `init(result:)` arm, and Kotlin's + `31 -> PlatformWallet.SigningKeyUnavailable` — all introduced by + `189a3abb1c` itself, so rule 5 was satisfied in the merging commit; +* 29 is still #4184's; 32 and 33 are still #4247/#4256's, which is why the trio + sits at 34–36; 37 is still #4204's; * nothing in flight has taken 28, 30, or 38; -* #4196 has restacked onto #4185 and now carries 34/35/36 rather than 26/27/28; -* #4247's head now also carries the 34/35/36 trio, inherited from #4185 (which - it is stacked on) rather than claimed a second time. +* #3968 is unchanged and still numbers 26 / 27 / 28; +* the two Swift mirror gaps this file was tracking — #4204's typed-case gap and + #4256's missing raw cases — have both been closed. -PR heads of record, all read on 2026-08-03: +PR heads of record, all read on 2026-08-04: | PR | Head | Note | | --- | --- | --- | -| #3954 | `93d0bd49b7` | Closed; superseded by #4268 | -| #3968 | `5931df745a` | Contains base `ed4116b26c` but **not** `5d68612a45` | -| #4183 | `8387858016` | Rebased onto `5d68612a45` on 2026-08-03; keeps 31 | -| #4184 | `5bdae75391` | Rebased onto `5d68612a45` on 2026-08-03; keeps 29 | -| #4185 | `8813e98533` | Post-34/35/36 move | -| #4186 | `951260520c` | | -| #4191 | `8acb0bd14c` | Touches only `dashpay.rs` in this crate | -| #4194 | `1d812c7297` | | -| #4195 | `c471dc9fe6` | | -| #4196 | `12492e8c54` | **Restacked onto #4185 on 2026-08-03**; trio now 34/35/36, MERGEABLE | -| #4204 | `d78b940a03` | Post-renumber 32 → 37; pre-#4268 base | -| #4240 | `3c19977a5a` | No file under this crate | -| #4243 | `f4be5b32f0` | Modifies `error.rs`, claims no integer | -| #4247 | `540def16a0` | Carries #4185's trio | -| #4251 | `176f8ed3eb` | No file under this crate | -| #4256 | `a456664278` | Post-34/35/36 move | -| #4258 | `ce8233edb7` | **Merged** 2026-08-03; claimed no code | -| #4259 | `9336bdbb71` | Carries #4183's 31 | +| #3954 | `31e22d5a90` | Closed; superseded by #4268 | +| #3968 | `5931df745a` | Head unchanged since 2026-08-03; still numbers 26 / 27 / 28. Contains base `ed4116b26c` but not `5d68612a45`, and so not `97904ed2fc` either | +| #4183 | `189a3abb1c` | **Merged 2026-08-04** (merge commit); 31 is now ABI | +| #4184 | `11c3677b1c` | Keeps 29 | +| #4185 | `326cd3eab6` | Trio at 34/35/36 | +| #4186 | `1fcdfd6b37` | Modifies `error.rs`; adds no discriminant | +| #4191 | `0e2282b586` | **Merged 2026-08-04** (merge commit); claimed no code | +| #4194 | `560f66a31d` | Modifies `error.rs`; adds no discriminant | +| #4195 | `7d20a638e5` | Modifies `error.rs`; adds no discriminant | +| #4196 | `9909f77546` | Restacked onto #4185; trio 34/35/36; allocates nothing of its own | +| #4204 | `4efecd5b71` | 37; rebased onto the merged base, so it now carries 27 and 31 from trunk; Swift mirror complete | +| #4240 | `a167afe84c` | No file under this crate | +| #4243 | `f4be5b32f0` | Head unchanged; modifies `error.rs`, claims no integer | +| #4247 | `8541073247` | 32, plus #4185's trio | +| #4251 | `7afc8a8ff3` | **Merged 2026-08-04** (merge commit); no file under this crate | +| #4256 | `862036b18d` | 32 / 33 plus the trio; Swift mirror now complete | +| #4258 | `ce8233edb7` | Merged 2026-08-03; claimed no code | +| #4259 | `5b77dfd8f1` | Carries 31 from the merged base | | #4264 | `bf88c92b85` | Closed; work carried by #4243 | +| #4277 | `6704a41a85` | **Merged 2026-08-04** (merge commit); modifies `error.rs`, claims no integer | Rows describing open PRs reflect those heads and go stale as the PRs are updated; the merged table does not. From b396767318df34eb67066f4417e1fc56d3f02e77 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 4 Aug 2026 15:07:34 -0400 Subject: [PATCH 10/22] docs(ffi): name ErrorTransactionBuild as the code-32 peer; qualify host outcomes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two corrections from the #4261 review round: - The code-32 collision peer was misidentified. #4204 defined ErrorShieldedInviteAlreadyClaimed = 32 (b6992a5dbc) and #4247 defines ErrorTransactionBuild = 32 (error.rs:257) — that is the E0081 pair. ErrorReservationWalletMismatch never held 32; its history runs 26/28 -> 30 -> 36. - "silently wrong on every host" overstated it. The three host outcomes differ and only one is a misclassification; spell them out. Also describe the inherited-code table as reduced to one row and retained for provenance rather than gone, since the row is rendered right below. Co-Authored-By: Claude Opus 4.8 --- .../ERROR_CODE_REGISTRY.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index f289cc4c59c..abf7bda5ea2 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -163,8 +163,8 @@ latter. "so no new numeric code churns the Swift/Kotlin mirror enums". The merged table is unchanged by it. -The **inherited-code table** that used to sit here is gone, and its single row is -worth recording rather than deleting: +The **inherited-code table** has been reduced to one row and retained for +provenance: | Code | Name | Carried by | Allocated to | | ---: | --- | --- | --- | @@ -228,7 +228,7 @@ also carried by #4256). Unlike every other entry in this section, this one was not a paper conflict: merging #4204 into an integration that already carried -`ErrorReservationWalletMismatch = 32` produced a hard +`ErrorTransactionBuild = 32` produced a hard `error[E0081]: discriminant value 32 assigned more than once`. Resolution of record: **#4204 moves 32 → 37**, the frontier. `ErrorTransactionBuild` keeps 32. @@ -236,9 +236,15 @@ The numbering was the lesser half of the defect. The code was **unmirrored on both hosts** — absent from Swift's `PlatformWalletResultCode` and from Kotlin's `fromPlatformWalletNative`. Per rule 5 that means Swift rendered it `.errorUnknown` (identity lost), while Kotlin fell through to `Generic(32, …)` -— and in any tree carrying #4185's `ErrorReservationWalletMismatch = 32`, -Kotlin actively **misclassified** "shielded invite already claimed" as -"reservation wallet mismatch". That is the exact silently-wrong-error-on-every-host +— and in any tree also carrying the competing #4247 mapping for 32, Kotlin +actively **misclassified** "shielded invite already claimed" as "transaction +build failed". `ErrorReservationWalletMismatch` was never the peer here: its +allocation history runs 26/28 → 30 → 36 and never passes through 32. + +The three host outcomes therefore differ, and only the third is a +misclassification: Swift loses the code's identity as `.errorUnknown`, Kotlin +on #4204 alone preserves `Generic(32, …)`, and Kotlin misclassifies only where +the competing code-32 mapping is also present. That is the cross-host ABI failure this file's preamble describes, and it landed on the shielded-invite claim-recovery path (the error is raised from four sites in `wallet/shielded/operations.rs`, three of them inside the recovery function). From b1a64870ac49f2107d8988569288c6a483267f30 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 4 Aug 2026 15:08:26 -0400 Subject: [PATCH 11/22] docs(ffi): finish the MD018 sweep for leading PR references Three leading `#` line starts survived the earlier sweep (lines 173, 177, 334) and markdownlint still read them as malformed ATX headings. markdownlint-cli2 now reports zero MD018 on this file. Co-Authored-By: Claude Opus 4.8 --- packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index abf7bda5ea2..39fa2136a14 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -170,11 +170,11 @@ provenance: | ---: | --- | --- | --- | | 31 | `ErrorSigningKeyUnavailable` | #4204, #4259 | #4183 | -#4183 merged on 2026-08-04, so 31 is no longer an allocation anyone can inherit +`#4183` merged on 2026-08-04, so 31 is no longer an allocation anyone can inherit — it is trunk. Every branch that has rebased onto current `v4.2-dev` carries it from the base, which is not a claim and cannot be double-counted. Verified 2026-08-04 at the heads of #4184, #4185, #4186, #4194, #4195, #4196, #4204, -#4240, #4247, #4256 and #4259: all eleven show `ErrorSigningKeyUnavailable = 31` +`#4240`, #4247, #4256 and #4259: all eleven show `ErrorSigningKeyUnavailable = 31` inherited from the merged base. PR `#4196` also claims no new integer: it adds a token-less @@ -331,7 +331,7 @@ Three branches have now done so: resolution of record. The equivalent stale comment on **#4204** is gone too. It was not fixed by hand: -#4204 rebased onto the merged base, and its `error.rs` at `4efecd5b71` now +`#4204` rebased onto the merged base, and its `error.rs` at `4efecd5b71` now carries #4183's corrected 28/29/30 note verbatim from trunk. All four branches that ever held the stale reservation text — #4256, #4183, #4184, #4204 — are clear, and #4183's version of the note is now trunk. From 68f7a3f3ea4ada56c2847b2ee6e68792ff5239c7 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 08:41:22 -0400 Subject: [PATCH 12/22] docs(ffi): migrate allocation ownership to the in-repo successor PRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proposed-allocations table named the fork-era owners (#4184, #4185, #4204, #4247, #4256), all closed when the estate was recreated in-repository. Ownership now names the active successors (29 -> #4316, 32 -> #4310, 33 -> #4311, 34-36 -> #4308, 37 -> #4313, carriers updated), the no-code inventory is marked as the fork-era snapshot it is, and the provenance base is date-stamped instead of claiming to be current. Collision history keeps the fork-era numbers — it is record. Co-Authored-By: Claude Fable 5 --- .../ERROR_CODE_REGISTRY.md | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 39fa2136a14..b551ac35a9b 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -117,25 +117,32 @@ the only allocation source and a new code takes 38. Not yet ABI. Numbers here may still move; they move by agreement recorded in this file. +**Ownership migrated 2026-08-11.** The fork-era PRs that originally held these +allocations (#4184, #4185, #4204, #4247, #4256) were closed and recreated +in-repository per repo policy; the owners below are the active successors. +Fork-era numbers remain in the collision history, which is immutable record. + | Code | Name | Owning PR | Status | | ---: | --- | --- | --- | | 28 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | -| 29 | `ErrorAssetLockInsufficientFunds` | #4184 | In review — **keeps 29** (collision resolved) | +| 29 | `ErrorAssetLockInsufficientFunds` | #4316 | In review — **keeps 29** (collision resolved; successor of fork-era #4184) | | 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | -| 32 | `ErrorTransactionBuild` | #4247 | In review (also carried by #4256) | -| 33 | `ErrorTransactionSigning` | #4256 | In review | -| 34 | `ErrorStaleReservationToken` | #4185 | In review — **moved 27 → 34** (also carried by #4256 and, post-restack, #4196) | -| 35 | `ErrorReservationTokenConsumed` | #4185 | In review — **moved 28 → 35** (also carried by #4256) | -| 36 | `ErrorReservationWalletMismatch` | #4185 | In review — **moved 30 → 36** (also carried by #4256) | -| 37 | `ErrorShieldedInviteAlreadyClaimed` | #4204 | In review — **moved 32 → 37** (collided with #4247's `ErrorTransactionBuild`; see below) | +| 32 | `ErrorTransactionBuild` | #4310 | In review (also carried by #4311; successor of fork-era #4247) | +| 33 | `ErrorTransactionSigning` | #4311 | In review (successor of fork-era #4256) | +| 34 | `ErrorStaleReservationToken` | #4308 | In review — **moved 27 → 34** (also carried by #4309, #4310 and #4311; successor of fork-era #4185) | +| 35 | `ErrorReservationTokenConsumed` | #4308 | In review — **moved 28 → 35** (also carried by #4309, #4310 and #4311; successor of fork-era #4185) | +| 36 | `ErrorReservationWalletMismatch` | #4308 | In review — **moved 30 → 36** (also carried by #4309, #4310 and #4311; successor of fork-era #4185) | +| 37 | `ErrorShieldedInviteAlreadyClaimed` | #4313 | In review — **moved 32 → 37** (collided with fork-era #4247's `ErrorTransactionBuild`; see below; successor of fork-era #4204) | **Code 31 left this table on 2026-08-04.** `ErrorSigningKeyUnavailable` sat here as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged table above and rule 3 applies to it in full. Nothing else in this table has merged, and the frontier is unchanged at 38. -Open PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified -2026-08-04 against each PR's file list and the `error.rs` at its head: +PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified +2026-08-04 against each PR's file list and the `error.rs` at its head (a +fork-era snapshot; #4186, #4194, #4195 and #4243 have since been closed and +recreated in-repository, carrying the same no-code property): `#3417`, `#3549`, `#3992`, `#4186`, `#4194`, `#4195`, `#4243`. Five entries this list used to carry have been removed, each for a stated @@ -192,9 +199,11 @@ allocation of record. A rebase is a precondition, not the remedy. `#3968`'s head does contain the 2026-08-01 base `ed4116b26c` (merge commit `debf67bdae` brought it in), so it is -not simply an un-rebased branch; it is behind the *current* base `97904ed2fc`, -which is where both #4268's merged `ErrorShutdownIncomplete = 27` and #4183's -merged `ErrorSigningKeyUnavailable = 31` live. Rebasing +not simply an un-rebased branch; it is behind the 2026-08-06 base +`97904ed2fc` (current when this analysis was recorded — the base has moved +since, which changes nothing below), which is where both #4268's merged +`ErrorShutdownIncomplete = 27` and #4183's merged +`ErrorSigningKeyUnavailable = 31` live. Rebasing picks those up, but rebasing alone will not resolve anything below, because git sees no conflict in any of it — the branch has to **edit its own enum**. From 34f5790fd12a21a867bf5204f8bf0a3775e06a44 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 09:30:00 -0400 Subject: [PATCH 13/22] docs(ffi): reconcile the registry with the merged 34-41 ABI The proposed-allocation era this file tracked has largely settled: #4308 merged the reservation trio (34-36, 438153da39), #4348 took 37-40 (6373e00f0c) and #4360 took 41 (e0b8baa850) - all now in the merged table. Codes 29/32/33 lapse to RESERVED (their in-repo owners closed without merging), the shielded-invite claim loses 37 to merged ABI and takes the frontier on revival, the frontier moves 38 -> 42, the #4196 'still outstanding' note is corrected to its 2026-08-03 close-out, and the 2026-08-04 heads-of-record table is labeled the historical snapshot it is. Co-Authored-By: Claude Fable 5 --- .../ERROR_CODE_REGISTRY.md | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index b551ac35a9b..d5805d45d86 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -100,39 +100,49 @@ These are shipped ABI. Do not renumber. | 26 | `ErrorTransactionBroadcastRejected` | Merged in `9302c62e8b`; took a number several open branches had been treating as free | | 27 | `ErrorShutdownIncomplete` | Merged 2026-08-02 by **#4268** (`429667e723`). A quiesce/drain barrier missed its budget. **Took the number #4185 had held since before this file existed** — see the collision history below | | 31 | `ErrorSigningKeyUnavailable` | Merged 2026-08-04 by **#4183** (merge commit `189a3abb1c`, stacked on #4191). The signer holds no usable private key for a requested public key. Landed complete in that one commit: the Rust C-facing discriminant, Swift's `errorSigningKeyUnavailable = 31` raw case *and* its `init(ffi:)` arm *and* the typed `PlatformWalletError` case with its `init(result:)` arm, and Kotlin's `31 -> PlatformWallet.SigningKeyUnavailable`. Rule 3 now protects it — see the 31-vs-33 note below | +| 34 | `ErrorStaleReservationToken` | Merged 2026-08-06 by **#4308** (`438153da39`) — the reservation trio landed with the split build/broadcast surface (successor of fork-era #4185's claim) | +| 35 | `ErrorReservationTokenConsumed` | Merged 2026-08-06 by **#4308** (`438153da39`) | +| 36 | `ErrorReservationWalletMismatch` | Merged 2026-08-06 by **#4308** (`438153da39`) | +| 37 | `ErrorDocumentNotForSale` | Merged 2026-08-09 by **#4348** (`6373e00f0c`). **Took the number the fork-era shielded-invite claim held** — see the proposed table's 37 note | +| 38 | `ErrorDocumentPriceChanged` | Merged 2026-08-09 by **#4348** (`6373e00f0c`) | +| 39 | `ErrorInsufficientIdentityCredits` | Merged 2026-08-09 by **#4348** (`6373e00f0c`) | +| 40 | `ErrorContestedNameNotTradable` | Merged 2026-08-09 by **#4348** (`6373e00f0c`) | +| 41 | `ErrorShieldedInsufficientBalance` | Merged 2026-08-11 by **#4360** (`e0b8baa850`) | | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next allocatable integer: 38** — 27–37 are all claimed (27 and 31 merged; 29 -and 32–37 in the proposed table below; 28 and 30 reserved). **28 and 30 are -RESERVED, not free**: #4185 and #4256 vacated them when the reservation trio -moved to 34–36, but they are deliberately left unclaimed rather than -back-filled, so that the trio stays contiguous and no number is reused within a -single review cycle. Rule 1's "do not reuse a gap unless this file marks it -free" applies — this file does **not** mark 28 or 30 free, so the frontier is -the only allocation source and a new code takes 38. +**Next allocatable integer: 42** — 27–41 are all claimed (27, 31, 34–41 +merged; 28–30, 32 and 33 reserved). **28–30, 32 and 33 are RESERVED, not +free**: 28 and 30 were vacated when the reservation trio moved to 34–36; 29, +32 and 33 lapsed when their in-repo owners (#4316, #4310, #4311) closed +without merging. All five are deliberately left unclaimed rather than +back-filled, so no number is reused within a single review cycle. Rule 1's +"do not reuse a gap unless this file marks it free" applies — this file does +**not** mark any of them free, so the frontier is the only allocation source +and a new code takes 42. ## Proposed allocations (open PRs) Not yet ABI. Numbers here may still move; they move by agreement recorded in this file. -**Ownership migrated 2026-08-11.** The fork-era PRs that originally held these -allocations (#4184, #4185, #4204, #4247, #4256) were closed and recreated -in-repository per repo policy; the owners below are the active successors. -Fork-era numbers remain in the collision history, which is immutable record. +**Ownership migrated 2026-08-11, then largely settled the same week.** The +fork-era PRs that originally held these allocations (#4184, #4185, #4204, +#4247, #4256) were closed and recreated in-repository per repo policy. Of the +successors: #4308 **merged** (the trio, 34–36 — now in the merged table); +#4316, #4310 and #4311 **closed without merging** (29, 32, 33 lapse to +RESERVED); and #4313 (the shielded-invite claim) lost 37 to merged #4348 and +takes the frontier when it revives. Fork-era numbers remain in the collision +history, which is immutable record. | Code | Name | Owning PR | Status | | ---: | --- | --- | --- | | 28 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | -| 29 | `ErrorAssetLockInsufficientFunds` | #4316 | In review — **keeps 29** (collision resolved; successor of fork-era #4184) | +| 29 | *(reserved — lapsed)* | — | Owner #4316 (successor of fork-era #4184) closed 2026-08-11 without merging; RESERVED, not reissuable | | 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | -| 32 | `ErrorTransactionBuild` | #4310 | In review (also carried by #4311; successor of fork-era #4247) | -| 33 | `ErrorTransactionSigning` | #4311 | In review (successor of fork-era #4256) | -| 34 | `ErrorStaleReservationToken` | #4308 | In review — **moved 27 → 34** (also carried by #4309, #4310 and #4311; successor of fork-era #4185) | -| 35 | `ErrorReservationTokenConsumed` | #4308 | In review — **moved 28 → 35** (also carried by #4309, #4310 and #4311; successor of fork-era #4185) | -| 36 | `ErrorReservationWalletMismatch` | #4308 | In review — **moved 30 → 36** (also carried by #4309, #4310 and #4311; successor of fork-era #4185) | -| 37 | `ErrorShieldedInviteAlreadyClaimed` | #4313 | In review — **moved 32 → 37** (collided with fork-era #4247's `ErrorTransactionBuild`; see below; successor of fork-era #4204) | +| 32 | *(reserved — lapsed)* | — | Owner #4310 (successor of fork-era #4247) closed without merging; RESERVED, not reissuable | +| 33 | *(reserved — lapsed)* | — | Owner #4311 (successor of fork-era #4256) closed without merging; RESERVED, not reissuable | +| 37→42 | `ErrorShieldedInviteAlreadyClaimed` | #4313 | On hold — its claim of 37 (a 32 → 37 move; successor of fork-era #4204) was **taken by merged #4348** (`ErrorDocumentNotForSale = 37`, ABI since 2026-08-09). On revival #4313 renumbers its Rust discriminant and Swift/Kotlin mappings to the frontier (42 at time of writing) | **Code 31 left this table on 2026-08-04.** `ErrorSigningKeyUnavailable` sat here as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged @@ -298,7 +308,8 @@ discriminant produce no textual conflict — the collision surfaces only as an E0081 after a textual merge, or silently as a wrong error code on the host. That is the whole reason this file exists. -**Still outstanding:** #4196 (see below). +**#4196 closed out 2026-08-03** — restacked onto the trio at 34/35/36 (see +"26 — RESOLVED" below); nothing remains outstanding from this collision. ### 30 — vacated, then RESERVED (not free) @@ -562,7 +573,9 @@ confirmed: * the two Swift mirror gaps this file was tracking — #4204's typed-case gap and #4256's missing raw cases — have both been closed. -PR heads of record, all read on 2026-08-04: +PR heads of record — a **historical snapshot, read 2026-08-04 (fork era)** +and retained as record; every non-merged PR below has since been closed and, +where still needed, recreated in-repository (see the migration note above): | PR | Head | Note | | --- | --- | --- | From 4568cd1dc3c53bad99be02ccc5c5126316ff5a41 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 09:39:26 -0400 Subject: [PATCH 14/22] docs(ffi): rewrap the migration note so no line opens with a PR reference (MD018) Co-Authored-By: Claude Fable 5 --- .../rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index d5805d45d86..3d1fda6c466 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -128,12 +128,12 @@ this file. **Ownership migrated 2026-08-11, then largely settled the same week.** The fork-era PRs that originally held these allocations (#4184, #4185, #4204, -#4247, #4256) were closed and recreated in-repository per repo policy. Of the -successors: #4308 **merged** (the trio, 34–36 — now in the merged table); -#4316, #4310 and #4311 **closed without merging** (29, 32, 33 lapse to -RESERVED); and #4313 (the shielded-invite claim) lost 37 to merged #4348 and -takes the frontier when it revives. Fork-era numbers remain in the collision -history, which is immutable record. +plus #4247 and #4256) were closed and recreated in-repository per repo +policy. Of the successors: #4308 **merged** (the trio, 34–36 — now in the +merged table); three others — #4316, #4310 and #4311 — **closed without +merging** (29, 32, 33 lapse to RESERVED); and #4313 (the shielded-invite +claim) lost 37 to merged #4348 and takes the frontier when it revives. +Fork-era numbers remain in the collision history, which is immutable record. | Code | Name | Owning PR | Status | | ---: | --- | --- | --- | From 56759f333576a37271ef3637f3c52aa2d041d6cd Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 10:35:17 -0400 Subject: [PATCH 15/22] =?UTF-8?q?docs(ffi):=20a=20held=20PR=20holds=20no?= =?UTF-8?q?=20number=20=E2=80=94=2042=20stays=20the=20public=20frontier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shielded-invite row both promised 42 to #4313-on-revival and named 42 the next allocatable integer, letting two contributors claim the same value. The held PR now explicitly holds nothing; it takes whatever the frontier is at revival, recording the claim here first. Co-Authored-By: Claude Fable 5 --- packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 3d1fda6c466..05586364660 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -142,7 +142,7 @@ Fork-era numbers remain in the collision history, which is immutable record. | 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 32 | *(reserved — lapsed)* | — | Owner #4310 (successor of fork-era #4247) closed without merging; RESERVED, not reissuable | | 33 | *(reserved — lapsed)* | — | Owner #4311 (successor of fork-era #4256) closed without merging; RESERVED, not reissuable | -| 37→42 | `ErrorShieldedInviteAlreadyClaimed` | #4313 | On hold — its claim of 37 (a 32 → 37 move; successor of fork-era #4204) was **taken by merged #4348** (`ErrorDocumentNotForSale = 37`, ABI since 2026-08-09). On revival #4313 renumbers its Rust discriminant and Swift/Kotlin mappings to the frontier (42 at time of writing) | +| 37→(frontier) | `ErrorShieldedInviteAlreadyClaimed` | #4313 | On hold — its claim of 37 (a 32 → 37 move; successor of fork-era #4204) was **taken by merged #4348** (`ErrorDocumentNotForSale = 37`, ABI since 2026-08-09). It holds **no number** while on hold: on revival it renumbers its Rust discriminant and Swift/Kotlin mappings to whatever this file's frontier is at that moment, recording the claim here first. 42 stays the public frontier until then | **Code 31 left this table on 2026-08-04.** `ErrorSigningKeyUnavailable` sat here as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged From e88336a8148498c225588db461d20fee3b6ee259 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 11:22:48 -0400 Subject: [PATCH 16/22] docs(ffi): code 29 is live under #4361; retire every stale code-38 frontier reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The registry called 29 lapsed, but #4361's head declares ErrorAssetLockInsufficientFunds = 29 — the typed asset-lock shortfall carried the allocation forward when #4316 closed. Row 29 now records the live owner and lineage. The remaining instructions that still pointed PR #3968 (and any new allocation) at the obsolete 38 frontier now point at the frontier note, and the 2026-08-04 verification checklist is date-stamped as the historical snapshot it is. Co-Authored-By: Claude Fable 5 --- .../ERROR_CODE_REGISTRY.md | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 05586364660..a6a6be0c94b 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -112,14 +112,14 @@ These are shipped ABI. Do not renumber. | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | **Next allocatable integer: 42** — 27–41 are all claimed (27, 31, 34–41 -merged; 28–30, 32 and 33 reserved). **28–30, 32 and 33 are RESERVED, not -free**: 28 and 30 were vacated when the reservation trio moved to 34–36; 29, -32 and 33 lapsed when their in-repo owners (#4316, #4310, #4311) closed -without merging. All five are deliberately left unclaimed rather than -back-filled, so no number is reused within a single review cycle. Rule 1's -"do not reuse a gap unless this file marks it free" applies — this file does -**not** mark any of them free, so the frontier is the only allocation source -and a new code takes 42. +merged; 29 proposed by active #4361; 28, 30, 32 and 33 reserved). **28, 30, +32 and 33 are RESERVED, not free**: 28 and 30 were vacated when the +reservation trio moved to 34–36; 32 and 33 lapsed when their in-repo owners +(#4310, #4311) closed without merging. All four are deliberately left +unclaimed rather than back-filled, so no number is reused within a single +review cycle. Rule 1's "do not reuse a gap unless this file marks it free" +applies — this file does **not** mark any of them free, so the frontier is +the only allocation source and a new code takes 42. ## Proposed allocations (open PRs) @@ -131,14 +131,15 @@ fork-era PRs that originally held these allocations (#4184, #4185, #4204, plus #4247 and #4256) were closed and recreated in-repository per repo policy. Of the successors: #4308 **merged** (the trio, 34–36 — now in the merged table); three others — #4316, #4310 and #4311 — **closed without -merging** (29, 32, 33 lapse to RESERVED); and #4313 (the shielded-invite +merging** (32 and 33 lapse to RESERVED; 29 is carried live by #4361, which +holds the typed shortfall today); and #4313 (the shielded-invite claim) lost 37 to merged #4348 and takes the frontier when it revives. Fork-era numbers remain in the collision history, which is immutable record. | Code | Name | Owning PR | Status | | ---: | --- | --- | --- | | 28 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | -| 29 | *(reserved — lapsed)* | — | Owner #4316 (successor of fork-era #4184) closed 2026-08-11 without merging; RESERVED, not reissuable | +| 29 | `ErrorAssetLockInsufficientFunds` | #4361 | In review — **keeps 29**. Lineage: fork-era #4184 → #4316 (closed unmerged) → carried live by #4361's typed asset-lock shortfall (`ErrorAssetLockInsufficientFunds = 29` at its head) | | 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 32 | *(reserved — lapsed)* | — | Owner #4310 (successor of fork-era #4247) closed without merging; RESERVED, not reissuable | | 33 | *(reserved — lapsed)* | — | Owner #4311 (successor of fork-era #4256) closed without merging; RESERVED, not reissuable | @@ -146,8 +147,10 @@ Fork-era numbers remain in the collision history, which is immutable record. **Code 31 left this table on 2026-08-04.** `ErrorSigningKeyUnavailable` sat here as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged -table above and rule 3 applies to it in full. Nothing else in this table has -merged, and the frontier is unchanged at 38. +table above and rule 3 applies to it in full. It has since had company: the +reservation trio (34–36, #4308) and the 37–41 block (#4348, #4360) also +merged out of proposal, and the frontier now sits at 42 — see the merged +table and the frontier note above. PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified 2026-08-04 against each PR's file list and the `error.rs` at its head (a @@ -230,8 +233,9 @@ which merged 27 into `v4.2-dev` on 2026-08-02. See the collision history below. PR `#3968` is the serious one: rule 3 forbids renumbering a code that has shipped, and `ErrorTransactionBroadcastRejected = 26` is merged ABI. Moving it to 28 would silently reinterpret every 26 an already-compiled host returns. -PR #3968 must keep 26 where it is and take fresh integers **from the frontier -(38+)** for its two persister codes. Its 27 is now doubly wrong: 27 is merged +PR #3968 must keep 26 where it is and take fresh integers **from the +frontier (42+ as of 2026-08-11 — check the frontier note above)** for its two +persister codes. Its 27 is now doubly wrong: 27 is merged ABI (`ErrorShutdownIncomplete`), so rule 3 protects it too. Note that 28 is reserved, not free — it is not available to #3968 either. @@ -388,7 +392,7 @@ The detail behind those rows: simply the merged base's, and there is no second claim to reconcile. PR `#3968` needs a rebase onto current `v4.2-dev` **and** fresh integers from -the frontier (**38+**). It must leave 26 alone; 27 is no longer available to it +the frontier (**42+**, per the frontier note above). It must leave 26 alone; 27 is no longer available to it either (merged ABI now), and neither are the reserved 28 and 30. ### 26 — RESOLVED: #4196 restacked onto #4185 and is on 34 / 35 / 36 @@ -555,7 +559,9 @@ ABI. Each of those four SHAs is the **merge commit on `v4.2-dev`**, confirmed by The 2026-08-04 pass re-read the discriminants directly, in-tree and at the *current* head of every open PR that touches `error.rs`, `DashSdkError.kt` or `PlatformWalletResult.swift`, and separately re-checked each PR's file list. It -confirmed: +confirmed — a **2026-08-04 verification snapshot, retained as record** (the +merged table and frontier note above are the current state; 34–41 have merged +since and the frontier is 42): * in-tree at `97904ed2fc`, `error.rs` runs 0–27 contiguously and then **31**, with 28, 29, 30 and everything from 32 up absent. So 31 is the only number From c49501765bd55e7c455b95650f5db004e5e378bb Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 12:09:19 -0400 Subject: [PATCH 17/22] docs(ffi): record #4356's live claim of 42; frontier advances to 43 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Open PR #4356 defines ErrorAssetLockInputConflict = 42 at its head with complete Swift/Kotlin mappings — the frontier this file advertised was already taken. Number-bearing side references now defer to the frontier note instead of naming a value that can go stale. Co-Authored-By: Claude Fable 5 --- .../ERROR_CODE_REGISTRY.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index a6a6be0c94b..067b4e5a034 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -111,15 +111,16 @@ These are shipped ABI. Do not renumber. | 98 | `NotFound` | Sentinel — `Option` returned as an error | | 99 | `ErrorUnknown` | Sentinel — unmapped/flattened errors | -**Next allocatable integer: 42** — 27–41 are all claimed (27, 31, 34–41 -merged; 29 proposed by active #4361; 28, 30, 32 and 33 reserved). **28, 30, +**Next allocatable integer: 43** — 27–42 are all claimed (27, 31, 34–41 +merged; 29 proposed by active #4361; 42 proposed by active #4356; 28, 30, +32 and 33 reserved). **28, 30, 32 and 33 are RESERVED, not free**: 28 and 30 were vacated when the reservation trio moved to 34–36; 32 and 33 lapsed when their in-repo owners (#4310, #4311) closed without merging. All four are deliberately left unclaimed rather than back-filled, so no number is reused within a single review cycle. Rule 1's "do not reuse a gap unless this file marks it free" applies — this file does **not** mark any of them free, so the frontier is -the only allocation source and a new code takes 42. +the only allocation source and a new code takes 43. ## Proposed allocations (open PRs) @@ -140,10 +141,11 @@ Fork-era numbers remain in the collision history, which is immutable record. | ---: | --- | --- | --- | | 28 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 29 | `ErrorAssetLockInsufficientFunds` | #4361 | In review — **keeps 29**. Lineage: fork-era #4184 → #4316 (closed unmerged) → carried live by #4361's typed asset-lock shortfall (`ErrorAssetLockInsufficientFunds = 29` at its head) | +| 42 | `ErrorAssetLockInputConflict` | #4356 | In review — claimed from the frontier with complete Swift/Kotlin mappings at head `7d9be71a08` | | 30 | *(reserved — vacated)* | — | Vacated by #4185/#4256 on 2026-08-02; RESERVED, not reissuable — the next-free frontier is the only allocation source | | 32 | *(reserved — lapsed)* | — | Owner #4310 (successor of fork-era #4247) closed without merging; RESERVED, not reissuable | | 33 | *(reserved — lapsed)* | — | Owner #4311 (successor of fork-era #4256) closed without merging; RESERVED, not reissuable | -| 37→(frontier) | `ErrorShieldedInviteAlreadyClaimed` | #4313 | On hold — its claim of 37 (a 32 → 37 move; successor of fork-era #4204) was **taken by merged #4348** (`ErrorDocumentNotForSale = 37`, ABI since 2026-08-09). It holds **no number** while on hold: on revival it renumbers its Rust discriminant and Swift/Kotlin mappings to whatever this file's frontier is at that moment, recording the claim here first. 42 stays the public frontier until then | +| 37→(frontier) | `ErrorShieldedInviteAlreadyClaimed` | #4313 | On hold — its claim of 37 (a 32 → 37 move; successor of fork-era #4204) was **taken by merged #4348** (`ErrorDocumentNotForSale = 37`, ABI since 2026-08-09). It holds **no number** while on hold: on revival it renumbers its Rust discriminant and Swift/Kotlin mappings to whatever this file's frontier is at that moment, recording the claim here first. The frontier (see the frontier note above) stays public until then | **Code 31 left this table on 2026-08-04.** `ErrorSigningKeyUnavailable` sat here as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged @@ -234,7 +236,7 @@ PR `#3968` is the serious one: rule 3 forbids renumbering a code that has shipped, and `ErrorTransactionBroadcastRejected = 26` is merged ABI. Moving it to 28 would silently reinterpret every 26 an already-compiled host returns. PR #3968 must keep 26 where it is and take fresh integers **from the -frontier (42+ as of 2026-08-11 — check the frontier note above)** for its two +frontier (43+ as of 2026-08-11 — check the frontier note above)** for its two persister codes. Its 27 is now doubly wrong: 27 is merged ABI (`ErrorShutdownIncomplete`), so rule 3 protects it too. Note that 28 is reserved, not free — it is not available to #3968 either. @@ -392,7 +394,7 @@ The detail behind those rows: simply the merged base's, and there is no second claim to reconcile. PR `#3968` needs a rebase onto current `v4.2-dev` **and** fresh integers from -the frontier (**42+**, per the frontier note above). It must leave 26 alone; 27 is no longer available to it +the frontier (**43+**, per the frontier note above). It must leave 26 alone; 27 is no longer available to it either (merged ABI now), and neither are the reserved 28 and 30. ### 26 — RESOLVED: #4196 restacked onto #4185 and is on 34 / 35 / 36 @@ -561,7 +563,7 @@ The 2026-08-04 pass re-read the discriminants directly, in-tree and at the `PlatformWalletResult.swift`, and separately re-checked each PR's file list. It confirmed — a **2026-08-04 verification snapshot, retained as record** (the merged table and frontier note above are the current state; 34–41 have merged -since and the frontier is 42): +since and the frontier has moved on — see the frontier note): * in-tree at `97904ed2fc`, `error.rs` runs 0–27 contiguously and then **31**, with 28, 29, 30 and everything from 32 up absent. So 31 is the only number From ce38a949a6c346864996fc13bc1267a13ea92803 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 12:18:19 -0400 Subject: [PATCH 18/22] docs(ffi): the last live frontier reference follows the note to 43 Co-Authored-By: Claude Fable 5 --- packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 067b4e5a034..d6ba43a0936 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -151,8 +151,8 @@ Fork-era numbers remain in the collision history, which is immutable record. as #4183's proposal until #4183 merged (`189a3abb1c`); it is now in the merged table above and rule 3 applies to it in full. It has since had company: the reservation trio (34–36, #4308) and the 37–41 block (#4348, #4360) also -merged out of proposal, and the frontier now sits at 42 — see the merged -table and the frontier note above. +merged out of proposal — see the merged table, and take the current +frontier only from the frontier note above (43 as of 2026-08-11). PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified 2026-08-04 against each PR's file list and the `error.rs` at its head (a From b94556d677e6d19ed1a5654e573764d45cf6d5b3 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:15:44 -0400 Subject: [PATCH 19/22] docs(ffi): close the code-33 decision, retire the fixed code-13 warning, unlist open #4243 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 31-vs-33 decision died with its owners (#4256 closed 2026-08-06, successor #4311 closed 2026-08-10): 33 is RESERVED, a revival chooses fresh. Code 13's stale rustdoc was already corrected in-tree by #4360. And #4243 is still open — it does not belong in the closed-and-recreated group. Co-Authored-By: Claude Fable 5 --- .../ERROR_CODE_REGISTRY.md | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index d6ba43a0936..83438697de0 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -84,7 +84,7 @@ These are shipped ABI. Do not renumber. | 10 | `ErrorInvalidIdentifier` | | | 11 | `ErrorMemoryAllocation` | | | 12 | `ErrorUtf8Conversion` | | -| 13 | `ErrorArithmeticOverflow` | Produced in-tree by `shielded_send.rs` (the shielded-send amount/fee overflow guard). The variant's own rustdoc still calls it a reserved slot with no producer and credits #3549 with the eventual mapping — that comment is stale and should be corrected by whichever PR touches it next | +| 13 | `ErrorArithmeticOverflow` | Produced in-tree by `shielded_send.rs` (the shielded-send amount/fee overflow guard). Its rustdoc was corrected by #4360 (`e0b8baa850`), which documents the `PlatformWalletError::InputSumOverflow` mapping — the stale no-producer comment this row used to track is gone | | 14 | `ErrorNoSelectableInputs` | | | 15 | `ErrorWalletAlreadyExists` | | | 16 | `ErrorShieldedBroadcastFailed` | | @@ -156,8 +156,9 @@ frontier only from the frontier note above (43 as of 2026-08-11). PRs that touch `rs-platform-wallet-ffi` but claim **no** new code, verified 2026-08-04 against each PR's file list and the `error.rs` at its head (a -fork-era snapshot; #4186, #4194, #4195 and #4243 have since been closed and -recreated in-repository, carrying the same no-code property): +fork-era snapshot; #4186, #4194 and #4195 have since been closed and +recreated in-repository, carrying the same no-code property, while #4243 +remains open at its fork-era head): `#3417`, `#3549`, `#3992`, `#4186`, `#4194`, `#4195`, `#4243`. Five entries this list used to carry have been removed, each for a stated @@ -452,14 +453,15 @@ key, restored from a typed signer completion code — whereas #4256's `BuilderError::SigningFailed` also covers unresolved derivation paths, sighash failures, and malformed signature encodings. -**That question is now half-settled by merging, not by agreement.** #4183 merged -on 2026-08-04, so **31 is ABI** and rule 3 forbids renumbering or retiring it; -it also ships with complete Swift and Kotlin mirrors, so hosts already -distinguish it. The only decision still open is #4256's: whether 33 stays a -separate code or `BuilderError::SigningFailed` is instead routed onto the -existing 31. That is #4256's alone to make now, and if it is made it should be -recorded here. What is no longer available is collapsing the pair *into* 33, or -moving 31 anywhere. +**That question is now fully settled — by merging and by closure, not by +agreement.** #4183 merged on 2026-08-04, so **31 is ABI** and rule 3 forbids +renumbering or retiring it; it ships with complete Swift and Kotlin mirrors. +The other side of the decision died with its owners: #4256 closed unmerged on +2026-08-06 and its in-repository successor #4311 closed unmerged on +2026-08-10, so no open PR holds the `BuilderError::SigningFailed` mapping and +33 sits RESERVED in the allocation table above. A future PR that revives that +mapping chooses fresh: route onto the existing 31 where the contract fits, or +claim a new code from the frontier — 33 itself is not reissuable. ## Collision history — the 27 / 28 / 30 → 34 / 35 / 36 move From 46f2442956fec85865de92c6006b3015659883f2 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:01:23 -0400 Subject: [PATCH 20/22] docs(ffi): stop calling the Aug-4 survey base the current head Co-Authored-By: Claude Fable 5 --- packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 83438697de0..293551739ac 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -551,7 +551,9 @@ Compiled 2026-08-01 against `v4.2-dev` at `ed4116b26c`, re-verified 2026-08-02 against `v4.2-dev` at `5d68612a45` (where `ErrorShutdownIncomplete = 27`, PR #4268 `429667e723`, entered the merged table), re-verified 2026-08-03 against that same base, and **re-verified again 2026-08-04 against `v4.2-dev` at -`97904ed2fc`**, which is the current head. +`97904ed2fc`** (the head on that date; the branch has advanced substantially +since — this whole section is the dated survey, and its merged/frontier +conclusions are superseded by the merged table and frontier note above). The base moved on 2026-08-04, which is what made that pass necessary: four PRs merged into `v4.2-dev` that day — **#4191** (`0e2282b586`), **#4183** From c3b2006f6d0701b5211f871910717739be815f11 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:42:34 -0400 Subject: [PATCH 21/22] =?UTF-8?q?docs(ffi):=20#3968=20and=20#4243=20are=20?= =?UTF-8?q?still=20open=20=E2=80=94=20don't=20sweep=20them=20into=20'all?= =?UTF-8?q?=20closed'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 293551739ac..5ceb3a91fe7 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -586,8 +586,10 @@ since and the frontier has moved on — see the frontier note): #4256's missing raw cases — have both been closed. PR heads of record — a **historical snapshot, read 2026-08-04 (fork era)** -and retained as record; every non-merged PR below has since been closed and, -where still needed, recreated in-repository (see the migration note above): +and retained as record. Most non-merged PRs below have since been closed and, +where still needed, recreated in-repository (see the migration note above) — +the exceptions being **#3968 and #4243, which GitHub still reports OPEN** (each +row notes its live status): | PR | Head | Note | | --- | --- | --- | From 6d6947ace77d5efa21d81c83bda032d410d47d94 Mon Sep 17 00:00:00 2001 From: bfoss765 <38437574+bfoss765@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:34:42 -0400 Subject: [PATCH 22/22] docs(ffi): record that #4308 reintroduced the 28/30-are-free comments The 'all branches clear' conclusion was true of the surveyed heads but merged #4308 later added Rust and Swift comments calling 28 and 30 free, against rule 1 and the primary table. The registry stays authoritative until an in-tree follow-up corrects them. Co-Authored-By: Claude Fable 5 --- .../rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md index 5ceb3a91fe7..b93b1489aaa 100644 --- a/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md +++ b/packages/rs-platform-wallet-ffi/ERROR_CODE_REGISTRY.md @@ -359,9 +359,17 @@ Three branches have now done so: The equivalent stale comment on **#4204** is gone too. It was not fixed by hand: `#4204` rebased onto the merged base, and its `error.rs` at `4efecd5b71` now -carries #4183's corrected 28/29/30 note verbatim from trunk. All four branches -that ever held the stale reservation text — #4256, #4183, #4184, #4204 — are -clear, and #4183's version of the note is now trunk. +carried #4183's corrected 28/29/30 note verbatim from trunk. All four branches +that ever held the stale reservation text — #4256, #4183, #4184, #4204 — were +clear at those surveyed heads, and #4183's version of the note became trunk. + +**The stale wording has since RETURNED to trunk.** Merged #4308 +(`438153da39`) introduced allocation comments that call 28 and 30 *free* — +`error.rs` ("28 (free — vacated by this PR)", "30 (free — …)", "28 and 30 are +nominally free") and the Swift mirror ("28 and 30 are free") — contradicting +rule 1 and the primary table, which RESERVE both values. Until a follow-up +corrects those in-tree comments, this registry is the authority: 28 and 30 +are reserved, not allocatable. ### 27 / 28 — #3968 still collides; #3954's claim merged as #4268