{
 "number": 36648,
 "input_hash": "19463266335ba04f",
 "model": "ledger",
 "prompt_hash": null,
 "created": "2026-11-02T01:11:55+00:00",
 "result": {
  "summary": "Stops echoing input key material and unparsed descriptor strings in error messages produced during descriptor parsing, wallet imports, and transaction funding. Replaces raw key echoes with generic descriptions, caps echoed tokens at lengths too short to contain keys, and prints public representations via desc->ToString() when available. Updates existing functional and unit tests to reflect the modified error strings and adds test coverage verifying private keys are omitted from errors.",
  "problem": "Descriptor inputs can include secret material such as WIF private keys or extended private keys (xprvs). When descriptor parsing or derivation fails, current error messages quote the raw input strings directly, exposing private keys to application logs, exception reporters, or support screenshots.",
  "card": "Prevents descriptor parsing and wallet RPC errors from echoing raw key material back to callers. Descriptors can contain private keys (WIF, xprv), and when parsing or derivation fails, current errors echo the input text, risking exposure in application logs, error aggregators, or screenshots. The change suppresses echoing raw key strings, restricts quoting of function names and path tokens to lengths that cannot fit key material, and prints sanitized public descriptors (desc->ToString()) where available. Tests are updated to assert the sanitized error messages and ensure no key prefixes leak.",
  "evidence": [
   "PR description: 'Some descriptor error messages quote the string the caller sent, and a descriptor can hold a private key (a WIF, an xprv). The reply then carries the key into places the request may not go: an application's error log, an error reporter, a screenshot shared for help. Even the first characters of a key give away part of it.'",
   "Commit a3f26e8343: 'Error text is often logged or shared where the request is not. Even the first characters of a key give away part of it.'"
  ],
  "scope_notes": "",
  "changed_since_previous": "No changes to the PR's contents; the patch is now provided where it was previously missing.",
  "thread": {
   "last_event_at": "2026-11-01T18:57:50Z",
   "events": 13,
   "head_sha": "a0217c4781f1be9eb6d2300df53656b6d6907379",
   "schema_floor": 2,
   "schema": 2
  },
  "waiting_on": [
   {
    "at": "2026-11-01",
    "id": "c:6562416965",
    "on": "reviewer",
    "url": "https://github.com/bitcoin/bitcoin/pull/36648#issuecomment-6562416965",
    "what": "uqlidi to review the author's responses and changes"
   }
  ],
  "risk": {
   "level": "medium",
   "touches": [
    "rpc_api",
    "wallet"
   ],
   "why": "Altering RPC error messages can break external scripts or wallet clients that rely on matching specific error string patterns."
  },
  "discussion": {
   "author_status": "last statement processed 2026-11-01",
   "open_concerns": [],
   "resolved_concerns": [
    "uqlidi: For expressions like 'wpkh(KEY)x', the error message incorrectly claims 'wpkh' is not a valid descriptor function instead of indicating that the problem is trailing characters (answered by fametrano 2026-11-01)",
    "uqlidi: Print the key's position or index in the error message when a key fails parsing in a multi-key descriptor so users do not have to check each key by hand (answered by fametrano 2026-11-01)",
    "uqlidi: Include the index of the failing descriptor in the error message when FundTransaction fails to parse a descriptor from solving_data (answered by fametrano 2026-11-01)",
    "uqlidi: Define MAX_QUOTED_CHARS once and reuse it across bip32.cpp and descriptor.cpp (answered by fametrano 2026-11-01)"
   ]
  },
  "reviewability": {
   "state": "Ready",
   "label": "CI failing",
   "reason": "CI is red; check whether the failure is the PR's before a deep review."
  },
  "agreement": {
   "state": "Positive",
   "summary": "Positive: support without stated reasons, no open objection (jpk68)",
   "reason": "The author responded to all four items raised by uqlidi, updating the error messages and explaining that MAX_QUOTED_CHARS was dropped.",
   "evidence": [
    "jpk68: ACK \u2014 no reason given"
   ],
   "objections": [
    {
     "reviewer": "uqlidi",
     "association": "NONE",
     "type": "objection",
     "kind": "interface",
     "harm": "For expressions like 'wpkh(KEY)x', the error message incorrectly claims 'wpkh' is not a valid descriptor function instead of indicating that the problem is trailing characters",
     "request": "",
     "question": "",
     "text": "For expressions like 'wpkh(KEY)x', the error message incorrectly claims 'wpkh' is not a valid descriptor function instead of indicating that the problem is trailing characters",
     "clears_with": "answer",
     "blocking": false,
     "status": "answered",
     "status_note": "author changed the error to note unexpected text after the closing parenthesis",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [
      "rc:4436906602"
     ],
     "evidence": "2026-10-28: 'wpkh is a valid function; the real problem is the trailing x'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36648#discussion_r4403942538",
     "id": "rc:4403942538",
     "at": "2026-10-28",
     "status_at": "2026-11-01",
     "status_by": "fametrano",
     "resolution_evidence": "2026-11-01: fametrano: 'Done: `wpkh(KEY)x` now gives `Unexpected text after the closing ')' of wpkh()`'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "uqlidi",
     "association": "NONE",
     "type": "suggestion",
     "kind": "interface",
     "harm": "",
     "request": "Print the key's position or index in the error message when a key fails parsing in a multi-key descriptor so users do not have to check each key by hand",
     "question": "",
     "text": "Print the key's position or index in the error message when a key fails parsing in a multi-key descriptor so users do not have to check each key by hand",
     "clears_with": "answer",
     "blocking": false,
     "status": "answered",
     "status_note": "author updated the error to state the key's 1-indexed position",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [
      "rc:4436908363",
      "rc:4436908470"
     ],
     "evidence": "2026-10-28: 'You can print the key's position.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36648#discussion_r4404122186",
     "id": "rc:4404122186",
     "at": "2026-10-28",
     "status_at": "2026-11-01",
     "status_by": "fametrano",
     "resolution_evidence": "2026-11-01: fametrano: 'Done: the error gives the key's position in its list, counted from 1'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "uqlidi",
     "association": "NONE",
     "type": "suggestion",
     "kind": "interface",
     "harm": "",
     "request": "Include the index of the failing descriptor in the error message when FundTransaction fails to parse a descriptor from solving_data",
     "question": "",
     "text": "Include the index of the failing descriptor in the error message when FundTransaction fails to parse a descriptor from solving_data",
     "clears_with": "answer",
     "blocking": false,
     "status": "answered",
     "status_note": "author included descriptor index in the error message",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [
      "rc:4436908572"
     ],
     "evidence": "2026-10-28: 'You can print its index in the list.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36648#discussion_r4404196067",
     "id": "rc:4404196067",
     "at": "2026-10-28",
     "status_at": "2026-11-01",
     "status_by": "fametrano",
     "resolution_evidence": "2026-11-01: fametrano: 'Done with your loop: `Unable to parse descriptor at index 1: Missing checksum`.'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "uqlidi",
     "association": "NONE",
     "type": "suggestion",
     "kind": "maintenance",
     "harm": "",
     "request": "Define MAX_QUOTED_CHARS once and reuse it across bip32.cpp and descriptor.cpp",
     "question": "",
     "text": "Define MAX_QUOTED_CHARS once and reuse it across bip32.cpp and descriptor.cpp",
     "clears_with": "answer",
     "blocking": false,
     "status": "answered",
     "status_note": "author replied that MAX_QUOTED_CHARS was removed entirely",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [
      "rc:4436908721"
     ],
     "evidence": "2026-10-28: 'you can define it here and reuse it inside descriptor.cpp'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36648#discussion_r4404226504",
     "id": "rc:4404226504",
     "at": "2026-10-28",
     "status_at": "2026-11-01",
     "status_by": "fametrano",
     "resolution_evidence": "2026-11-01: fametrano: '`MAX_QUOTED_CHARS` is gone: no error quotes text by length any more'",
     "pin": null,
     "from_schema": 2
    }
   ],
   "support": [
    {
     "reviewer": "jpk68",
     "reason": "no reason given",
     "substantive": false,
     "verdict": "ACK",
     "id": "c:6452939364",
     "url": "https://github.com/bitcoin/bitcoin/pull/36648#issuecomment-6452939364",
     "at": "2026-10-27",
     "association": "CONTRIBUTOR",
     "evidence": "none",
     "areas": []
    }
   ],
   "participants": [
    {
     "login": "jpk68",
     "stance": "support",
     "note": "ACK with commit hash",
     "association": "CONTRIBUTOR",
     "comments": 1,
     "first": "2026-10-27",
     "last": "2026-10-27"
    },
    {
     "login": "uqlidi",
     "stance": "objection",
     "note": "objected to inaccurate error messages for trailing characters after descriptor functions; suggested printing key and descriptor indices and deduplicating constants",
     "association": "NONE",
     "comments": 6,
     "first": "2026-10-28",
     "last": "2026-10-28"
    }
   ],
   "derivation": "support without stated reasons, no open objection (jpk68)",
   "model_state": null,
   "corrections": [],
   "notes": "The author responded to all four items raised by uqlidi, updating the error messages and explaining that MAX_QUOTED_CHARS was dropped."
  },
  "dependencies": {
   "depends_on": [],
   "enables": []
  },
  "categories": [
   {
    "name": "p2p",
    "member": false,
    "evidence": "Candidate based solely on false keyword matches; the PR touches descriptor parsing and RPC/wallet error handling.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "Does not touch P2P networking code."
   },
   {
    "name": "rpc",
    "member": true,
    "evidence": "Changes RPC utility error reporting in src/rpc/util.cpp and modifies RPC error responses for descriptor methods to avoid echoing secret keys.",
    "band": "P2",
    "reason_tag": "bug fix",
    "score": 0.65,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "Prevents exposure of sensitive key material via RPC error replies that can be captured in application logs or shared bug reports. The PR description notes that error messages currently 'quote the raw input strings directly, exposing private keys to application logs, exception reporters, or support screenshots', directly addressing RPC interface data exposure."
   },
   {
    "name": "tools",
    "member": false,
    "evidence": "Candidate based on incidental keyword matches; the PR does not target CLI tools or contrib scripts.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "Does not touch offline tools or contrib scripts."
   },
   {
    "name": "utils",
    "member": false,
    "evidence": "Only touches src/util/bip32.cpp with two lines as a mechanical consequence of descriptor error handling rather than changing shared utility infrastructure.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "The minor tweak in bip32 utility code is incidental to descriptor and wallet error sanitization."
   },
   {
    "name": "wallet",
    "member": true,
    "evidence": "Modifies error handling during descriptor imports and transaction funding in src/wallet/imports.cpp and src/wallet/rpc/spend.cpp.",
    "band": "P2",
    "reason_tag": "bug fix",
    "score": 0.65,
    "factors": {
     "bug_severity": 2,
     "leverage": 0,
     "performance": 0,
     "security_stability": 2,
     "user_value": 1
    },
    "rationale": "Stops leaking private keys (WIF, xprvs) in error messages when importing descriptors or funding transactions. The author notes that 'a descriptor can hold a private key' and 'the reply then carries the key into places the request may not go', safeguarding key confidentiality during wallet failures."
   }
  ],
  "confidence": "high",
  "uncertainties": [],
  "needs": []
 },
 "cost_usd": 0.0,
 "source": {
  "record": "2026-11-02T01:11:55+00:00",
  "code": "2026-10-26T01:25:16+00:00",
  "judgments": 5
 }
}