{
 "number": 36583,
 "input_hash": "44f5f05d0e6363f0",
 "model": "ledger",
 "prompt_hash": null,
 "created": "2026-10-23T01:19:19+00:00",
 "result": {
  "summary": "Fixes migration of watch-only legacy wallets with transactions during `migratewallet`. It guards database transaction listener execution so unset callbacks are skipped rather than throwing `std::bad_function_call` on commit or abort, and updates the watch-only migration check to account for transaction records queued for deletion.",
  "problem": "Migrating a legacy wallet containing watch-only addresses and transaction records always fails. `CWallet::ApplyMigrationData()` expects in-memory `mapWallet` to be empty before the transaction commit listener has actually purged them, which triggers an abort; calling `TxnAbort()` then unconditionally invokes an unset `on_abort` callback registered by `RemoveTxs()`, throwing an unhandled `std::bad_function_call` that bypasses migration cleanup.",
  "card": "This PR fixes a bug preventing legacy watch-only wallets containing transaction records from being migrated to descriptor wallets via migratewallet. Currently, ApplyMigrationData checks whether mapWallet is empty before database commit listeners have cleared it, triggering an abort that throws std::bad_function_call because on_abort is unset. The patch skips unset transaction listeners and validates that all transactions are queued for deletion, resolving issue #36483.",
  "evidence": [
   "Issue #36483 reports 'wallet: Migration fails for legacy wallet with no keys watching an address'",
   "PR description explains the two bugs: 'mapWallet is therefore never empty at that point and the check always fails' and 'TxnCommit() and TxnAbort() each invoked their listener's callback unconditionally, so the abort triggered by the failed check above threw std::bad_function_call.'"
  ],
  "scope_notes": "",
  "changed_since_previous": "No functional changes; diff confirms the previous description.",
  "thread": {
   "last_event_at": "2026-10-22T06:47:34Z",
   "events": 1,
   "head_sha": "50f254e53ac357e5a8315062c634e36071e1aa19",
   "schema_floor": 2,
   "schema": 2
  },
  "waiting_on": [
   {
    "at": null,
    "id": "",
    "on": "reviewer",
    "url": null,
    "what": "initial review"
   }
  ],
  "risk": {
   "level": "medium",
   "touches": [
    "wallet",
    "wallet_storage"
   ],
   "why": "A flaw in wallet database transaction listener handling or migration verification could leave wallets partially migrated or corrupt wallet database state."
  },
  "discussion": {
   "author_status": "last statement processed 2026-10-22",
   "open_concerns": [],
   "resolved_concerns": []
  },
  "reviewability": {
   "state": "Ready",
   "label": "Ready",
   "reason": "Nothing known that would invalidate a review now."
  },
  "agreement": {
   "state": "Crickets",
   "summary": "Crickets: no substantive comment either way",
   "reason": "Initial record. Naomi-Gift left an untested ACK without rationale, which is not counted as support because the account has no history in the project. / Initial record. Naomi-Gift left a utACK with no rationale; as an account with no history in the project, it is not recorded as support.",
   "evidence": [],
   "objections": [],
   "support": [],
   "participants": [
    {
     "login": "Naomi-Gift",
     "stance": "support",
     "note": "utACK with no rationale from account with no project history",
     "association": "NONE",
     "comments": 1,
     "first": "2026-10-22",
     "last": "2026-10-22"
    }
   ],
   "derivation": "no substantive comment either way",
   "model_state": null,
   "corrections": [],
   "notes": "Initial record. Naomi-Gift left an untested ACK without rationale, which is not counted as support because the account has no history in the project. / Initial record. Naomi-Gift left a utACK with no rationale; as an account with no history in the project, it is not recorded as support."
  },
  "dependencies": {
   "depends_on": [],
   "enables": []
  },
  "categories": [
   {
    "name": "wallet",
    "member": true,
    "evidence": "Matches Wallet label and modifies wallet migration logic in src/wallet/wallet.cpp and transaction listener callbacks in src/wallet/walletdb.cpp.",
    "band": "P2",
    "reason_tag": "bug fix",
    "score": 0.72,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 2
    },
    "rationale": "Fixes a deterministic failure and unhandled exception during legacy-to-descriptor wallet migration for watch-only wallets with transactions. Migrating these wallets currently fails when checking if `mapWallet` is empty and subsequently throws `std::bad_function_call` during `TxnAbort()` because listener callbacks are unset, preventing migration and bypassing cleanup."
   }
  ],
  "confidence": "high",
  "uncertainties": [],
  "needs": []
 },
 "cost_usd": 0.0,
 "source": {
  "record": "2026-10-23T01:19:19+00:00",
  "code": "2026-10-22T01:18:43+00:00",
  "judgments": 1
 }
}