{
 "number": 36257,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36257",
 "title": "qa: assert_equals -> assert_true/assert_false",
 "author": "hodlinator",
 "author_association": "MEMBER",
 "created_at": "2026-09-15T07:45:35Z",
 "updated_at": "2026-09-16T10:06:31Z",
 "age_days": 2,
 "draft": false,
 "labels": [
  "Tests"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c",
 "head_ref": "2026/09/assert_true",
 "head_repo": "hodlinator/bitcoin",
 "head_history": [
  {
   "t": "2026-09-15T20:09:07Z",
   "sha": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c"
  }
 ],
 "additions": 637,
 "deletions": 511,
 "changed_files": 93,
 "commit_count": 5,
 "size_bucket": "XL",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {},
   "conflicts": [
    {
     "number": 36192,
     "title": "test: cover unsatisfiable mining timestamp",
     "author": "Sjors"
    },
    {
     "number": 36170,
     "title": "net: require a dedicated bind for automatic Tor",
     "author": "l0rinc"
    },
    {
     "number": 36097,
     "title": "mining: replace interrupt methods with cancellation arguments",
     "author": "xyzconstant"
    },
    {
     "number": 35940,
     "title": "net: allow selecting BIP152 high-bandwidth peers with `-addnode`",
     "author": "w0xlt"
    },
    {
     "number": 35920,
     "title": "net_processing: Ignore MSG_WITNESS_TX entries from INV messages",
     "author": "ajtowns"
    },
    {
     "number": 35837,
     "title": "rpc: fail scanblocks when block filter range is unavailable",
     "author": "MicSm"
    },
    {
     "number": 35377,
     "title": "wallet: Allow importing of descriptors without private keys when the wallet has the private keys",
     "author": "achow101"
    },
    {
     "number": 35301,
     "title": "Silent Payments: Implement bip352 (take 2)",
     "author": "Eunovo"
    },
    {
     "number": 34371,
     "title": "wallet: allow importprunedfunds for spending transactions",
     "author": "8144225309"
    },
    {
     "number": 34038,
     "title": "logging: replace -loglevel with -trace, expose trace logging via RPC",
     "author": "ajtowns"
    },
    {
     "number": 33922,
     "title": "mining: add getMemoryLoad() and track template non-mempool memory footprint",
     "author": "Sjors"
    },
    {
     "number": 33112,
     "title": "wallet: relax external_signer flag constraints",
     "author": "Sjors"
    },
    {
     "number": 32857,
     "title": "wallet: allow skipping script paths",
     "author": "Sjors"
    },
    {
     "number": 31668,
     "title": "Added rescan option for import descriptors",
     "author": "saikiran57"
    },
    {
     "number": 27865,
     "title": "wallet: Track no-longer-spendable TXOs separately",
     "author": "achow101"
    }
   ]
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "l0rinc",
   "maflcko"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-16T10:06:31Z",
  "last_reviewer_activity": "2026-09-16T09:19:03Z",
  "last_reviewer": "maflcko",
  "author_silent_days": 1,
  "waiting_on_author_days": 0,
  "days_since_update": 1
 },
 "refs": {
  "mentioned": [
   31874
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 31874,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-03-27",
    "title": "qa wallet: Activate dormant checks in wallet_multisig_descriptor_psbt.py"
   }
  ],
  "conflicts": [
   36192,
   36170,
   36097,
   35940,
   35920,
   35837,
   35377,
   35301,
   34371,
   34038,
   33922,
   33112,
   32857,
   31668,
   27865
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "test/functional/test_framework/util.py"
 ],
 "body": "Instead of this in the functional tests:\n```python\n    assert_equals([long expression pushing next arg to the right], True)\n    assert_equals([other long expression pushing next arg to the right], False)\n```\nwe get:\n```python\n    assert_true([long expression without arg on the right side..])\n    assert_false([other long expression without next arg to the right.])\n```\n\nThe main point of this change is that `assert_true()`/`assert_false()` reduce cognitive tokens when scanning the code (equals to *what*...?). (As a consequence, `assert_true()`/`assert_false()` are also common in other test frameworks).\n\n`assert_equals()` continues to be used in cases where we don't compare to boolean literals.\n\n`assert_true([expression])` is different from plain `assert [expression]` in that `assert` is truthy while `assert_true` requires boolean `True`. (`assert` can also be deactivated when executing Python code in optimized mode (see https://github.com/bitcoin/bitcoin/pull/30529#discussion_r1893029530)).\n\nA smaller scale attempt at introducing `assert_true()` was originally included in #31874 before being dropped.",
 "commits": [
  {
   "sha": "486d0027e54c936c741af7799396572b54df06c0",
   "date": "2026-09-15T19:48:21Z",
   "message": "qa: Add assert_true() / assert_false()"
  },
  {
   "sha": "acef9ecdae0429a3874f9bc4525c661e07c3f9f6",
   "date": "2026-09-15T19:48:46Z",
   "message": "qa: Fix weird case of 3-arg assert_equal() ahead of scripted diff\n\nBefore 2ef6679c2ca87bbe305f45ff3df3d19ec3f60595 introduced finalized2 we had:\nassert_equal(finalized[\"complete\"], True)\n...so this is changing things back towards that."
  },
  {
   "sha": "f27214f16d34d0cc109439cafd2d28b89729fa14",
   "date": "2026-09-15T19:48:46Z",
   "message": "qa: Fixup imports ahead of scripted diff"
  },
  {
   "sha": "bd1776c028994918958f3bfedab2862d9ab8e971",
   "date": "2026-09-15T19:48:46Z",
   "message": "scripted-diff: Replace assert_equals([..., ]True/False[, ...]) with assert_true/assert_false\n\n-BEGIN VERIFY SCRIPT-\nsed -i -E \"s/assert_equal\\((.*)\\, (True|False)\\)( *(#.*))?$/assert_\\L\\2(\\E\\1)\\3/g\" $( git grep -lE \"assert_equal\\(.*, (True|False)\\)\"  -- test/functional/ )\nsed -i -E \"s/assert_equal\\((True|False), (.*)$/assert_\\L\\1\\E\\(\\2/g\" $( git grep -lE \"assert_equal\\((True|False)\"  -- test/functional/ )\n-END VERIFY SCRIPT-"
  },
  {
   "sha": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c",
   "date": "2026-09-15T19:48:46Z",
   "message": "qa: Remove no longer used assert_equals imports"
  }
 ],
 "timeline": [
  {
   "t": "2026-09-15T18:47:44Z",
   "kind": "review_comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "path": "test/functional/test_framework/util.py",
   "commit": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c",
   "in_reply_to": null,
   "text": "[quoted text omitted]\n\nThe first commit introduces dead code; there are no users of the new methods, so I have to go through the next commits to tell if these are fully correct or not.\n\nBut even just looking at these, I don't like that they do something other than what they claim: they're not actually asserting `True`, but rather truthiness, which doesn't seem to be documented here. Maybe renaming to `truthy` and `falsy` would be more predictable.\n\nI would also like to see tests added to explain their behavior, since otherwise the actual test cases are the test for the new helper method, and both could be incorrect and we wouldn't know. Just a few simple ones with primitives would suffice."
  },
  {
   "t": "2026-09-15T18:54:35Z",
   "kind": "review",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "14ed48a395d026b85b229d917008f125ceae85d7",
   "text": "I don't mind the change, the only reason I see to use explicit `True` and `False` is to flip these after a characterization test - but they could also flip the method name.\n\nBased on https://mirror.b10c.me/bitcoin-bitcoin/34773#discussion_r3009767675 and https://mirror.b10c.me/bitcoin-bitcoin/34773#discussion_r3009771746, @maflcko might be interested."
  },
  {
   "t": "2026-09-15T20:09:07Z",
   "kind": "force_push",
   "who": "hodlinator",
   "commit": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c"
  },
  {
   "t": "2026-09-15T20:09:23Z",
   "kind": "review_comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "path": "test/functional/test_framework/util.py",
   "commit": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c",
   "in_reply_to": 4019082601,
   "text": "re https://github.com/bitcoin/bitcoin/pull/36257#discussion_r4019082601:\n\nThanks for catching the accidental degradation in correctness! I originally used `!= True`/`!= False` but the ruff linter recommended the truthy/falsy variants. `is not` seems to fit the bill without angering ruff.\n\nYou can patch the test_runner with this and run it to verify the latest push is more correct:\n\nDiff\n\n```diff\n--- a/test/functional/test_runner.py\n+++ b/test/functional/test_runner.py\n@@ -30,6 +30,8 @@ import tempfile\n import re\n import logging\n from test_framework.util import (\n+    assert_false,\n+    assert_true,\n     Binaries,\n     export_env_build_path,\n     get_binary_paths,\n@@ -967,4 +969,52 @@ class RPCCoverage():\n\n if __name__ == '__main__':\n-    main()\n+    assert_false(False)\n+    assert_true(True)\n+\n+    try:\n+        assert_false(True)\n+    except AssertionError:\n+        pass\n+    else:\n+        raise AssertionError(\"assert_false(True) should raise\")\n+\n+    try:\n+        assert_true(False)\n+    except AssertionError:\n+        pass\n+    else:\n+        raise AssertionError(\"assert_true(False) should raise\")\n+\n+\n+    # Test falsyness\n+    try:\n+        assert_false(list())\n+    except AssertionError:\n+        pass\n+    else:\n+        raise AssertionError(\"assert_false is falsy\")\n+\n+    try:\n+        assert_false([1, 2])\n+    except AssertionError:\n+        pass\n+    else:\n+        raise AssertionError(\"assert_false is broken\")\n+\n+    # Test truthyness\n+    try:\n+        assert_true([1, 2])\n+    except AssertionError:\n+        pass\n+    else:\n+        raise AssertionError(\"assert_true is truthy\")\n+\n+    try:\n+        assert_true(list())\n+    except AssertionError:\n+        pass\n+    else:\n+        raise AssertionError(\"assert_true is broken\")\n+\n+    print(\"assert_false/assert_true have expected behavior!\")\n```\n\nNone of the other util methods have these meta-tests AFAIK. If you insist do you have any suggestion for where to start adding them?\n\nRegarding adding them as dead code, it's a natural effect of having to add them before the scripted diff. (Only with the exception of one wallet test in \"qa: Fix weird case of 3-arg assert_equal() ahead of scripted diff\")."
  },
  {
   "t": "2026-09-15T20:20:27Z",
   "kind": "review",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c",
   "text": "[quoted text omitted]\n\nIt was reviewing your characterization test flipping which made me flip and implement this. :)"
  },
  {
   "t": "2026-09-16T09:19:03Z",
   "kind": "comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThis isn't wrong, but seems to be missing the point: The reason why assert_equal with `True` or `False` is used is not because `assert` may dropped (in theory, no one is doing this in practise?), but rather that the assert only checks truthy/falsy states, not type-safe equality.\n\nSo the only real remaining motivation for this is to reduce code bloat. No objection, but overall I am ~0 on this."
  },
  {
   "t": "2026-09-16T10:06:31Z",
   "kind": "comment",
   "who": "hodlinator",
   "assoc": "MEMBER",
   "text": "Thanks for having a look @maflcko. Re-orged the PR desc to add the truthyness nuance of `assert` and also to make the cognitive part more prominent as the motivation."
  }
 ],
 "labels_log": [
  {
   "t": "2026-09-15T07:45:38Z",
   "action": "labeled",
   "label": "Tests",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 5903,
 "text_tokens_estimate": 1475,
 "changed_paths": [
  "test/functional/feature_addrman.py",
  "test/functional/feature_assumeutxo.py",
  "test/functional/feature_block.py",
  "test/functional/feature_discover.py",
  "test/functional/feature_fee_estimation.py",
  "test/functional/feature_maxtipage.py",
  "test/functional/feature_minchainwork.py",
  "test/functional/feature_notifications.py",
  "test/functional/feature_proxy.py",
  "test/functional/feature_rbf.py",
  "test/functional/interface_ipc_mining.py",
  "test/functional/interface_rest.py",
  "test/functional/interface_usdt_coinselection.py",
  "test/functional/interface_usdt_mempool.py",
  "test/functional/interface_usdt_utxocache.py",
  "test/functional/mempool_accept.py",
  "test/functional/mempool_datacarrier.py",
  "test/functional/mempool_dust.py",
  "test/functional/mempool_sigoplimit.py",
  "test/functional/mempool_unbroadcast.py",
  "test/functional/mining_template_verification.py",
  "test/functional/p2p_addr_relay.py",
  "test/functional/p2p_blocksonly.py",
  "test/functional/p2p_compactblocks_blocksonly.py",
  "test/functional/p2p_compactblocks_hb.py",
  "test/functional/p2p_disconnect_ban.py",
  "test/functional/p2p_ibd_stalling.py",
  "test/functional/p2p_segwit.py",
  "test/functional/p2p_sendheaders.py",
  "test/functional/p2p_tx_download.py",
  "test/functional/p2p_unrequested_blocks.py",
  "test/functional/rpc_blockchain.py",
  "test/functional/rpc_createmultisig.py",
  "test/functional/rpc_gettxspendingprevout.py",
  "test/functional/rpc_misc.py",
  "test/functional/rpc_net.py",
  "test/functional/rpc_openrpc.py",
  "test/functional/rpc_psbt.py",
  "test/functional/rpc_rawtransaction.py",
  "test/functional/rpc_scanblocks.py",
  "test/functional/rpc_scantxoutset.py",
  "test/functional/rpc_signer.py",
  "test/functional/rpc_signrawtransactionwithkey.py",
  "test/functional/rpc_validateaddress.py",
  "test/functional/test_framework/test_framework.py",
  "test/functional/test_framework/util.py",
  "test/functional/test_framework/wallet.py",
  "test/functional/tool_wallet.py",
  "test/functional/wallet_abandonconflict.py",
  "test/functional/wallet_address_types.py",
  "test/functional/wallet_anchor.py",
  "test/functional/wallet_ancient_migration.py",
  "test/functional/wallet_assumeutxo.py",
  "test/functional/wallet_avoidreuse.py",
  "test/functional/wallet_backwards_compatibility.py",
  "test/functional/wallet_balance.py",
  "test/functional/wallet_basic.py",
  "test/functional/wallet_blank.py",
  "test/functional/wallet_bumpfee.py",
  "test/functional/wallet_createwallet.py",
  "test/functional/wallet_createwalletdescriptor.py",
  "test/functional/wallet_deprecated_rbf.py",
  "test/functional/wallet_derivehdkey.py",
  "test/functional/wallet_descriptor.py",
  "test/functional/wallet_disable.py",
  "test/functional/wallet_encryption.py",
  "test/functional/wallet_exported_watchonly.py",
  "test/functional/wallet_fundrawtransaction.py",
  "test/functional/wallet_gethdkeys.py",
  "test/functional/wallet_hd.py",
  "test/functional/wallet_importdescriptors.py",
  "test/functional/wallet_importprunedfunds.py",
  "test/functional/wallet_keypool.py",
  "test/functional/wallet_labels.py",
  "test/functional/wallet_listreceivedby.py",
  "test/functional/wallet_listsinceblock.py",
  "test/functional/wallet_listtransactions.py",
  "test/functional/wallet_migration.py",
  "test/functional/wallet_miniscript.py",
  "test/functional/wallet_miniscript_decaying_multisig_descriptor_psbt.py",
  "test/functional/wallet_multiwallet.py",
  "test/functional/wallet_musig.py",
  "test/functional/wallet_orphanedreward.py",
  "test/functional/wallet_reorgsrestore.py",
  "test/functional/wallet_resendwallettransactions.py",
  "test/functional/wallet_send.py",
  "test/functional/wallet_sendall.py",
  "test/functional/wallet_signer.py",
  "test/functional/wallet_signrawtransactionwithwallet.py",
  "test/functional/wallet_simulaterawtx.py",
  "test/functional/wallet_transactiontime_rescan.py",
  "test/functional/wallet_txn_clone.py",
  "test/functional/wallet_txn_doublespend.py"
 ],
 "files": [
  {
   "path": "test/functional/feature_addrman.py",
   "add": 3,
   "del": 3
  },
  {
   "path": "test/functional/feature_assumeutxo.py",
   "add": 7,
   "del": 5
  },
  {
   "path": "test/functional/feature_block.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/feature_discover.py",
   "add": 2,
   "del": 2
  },
  {
   "path": "test/functional/feature_fee_estimation.py",
   "add": 11,
   "del": 9
  },
  {
   "path": "test/functional/feature_maxtipage.py",
   "add": 3,
   "del": 3
  },
  {
   "path": "test/functional/feature_minchainwork.py",
   "add": 3,
   "del": 2
  },
  {
   "path": "test/functional/feature_notifications.py",
   "add": 5,
   "del": 4
  },
  {
   "path": "test/functional/feature_proxy.py",
   "add": 25,
   "del": 25
  },
  {
   "path": "test/functional/feature_rbf.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/interface_ipc_mining.py",
   "add": 15,
   "del": 13
  },
  {
   "path": "test/functional/interface_rest.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/interface_usdt_coinselection.py",
   "add": 7,
   "del": 5
  },
  {
   "path": "test/functional/interface_usdt_mempool.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/interface_usdt_utxocache.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/mempool_accept.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/mempool_datacarrier.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/mempool_dust.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/mempool_sigoplimit.py",
   "add": 4,
   "del": 3
  },
  {
   "path": "test/functional/mempool_unbroadcast.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/mining_template_verification.py",
   "add": 3,
   "del": 2
  },
  {
   "path": "test/functional/p2p_addr_relay.py",
   "add": 12,
   "del": 10
  },
  {
   "path": "test/functional/p2p_blocksonly.py",
   "add": 10,
   "del": 10
  },
  {
   "path": "test/functional/p2p_compactblocks_blocksonly.py",
   "add": 3,
   "del": 3
  },
  {
   "path": "test/functional/p2p_compactblocks_hb.py",
   "add": 2,
   "del": 2
  },
  {
   "path": "test/functional/p2p_disconnect_ban.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/p2p_ibd_stalling.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/p2p_segwit.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/p2p_sendheaders.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/p2p_tx_download.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/p2p_unrequested_blocks.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/rpc_blockchain.py",
   "add": 6,
   "del": 5
  },
  {
   "path": "test/functional/rpc_createmultisig.py",
   "add": 4,
   "del": 3
  },
  {
   "path": "test/functional/rpc_gettxspendingprevout.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/rpc_misc.py",
   "add": 8,
   "del": 6
  },
  {
   "path": "test/functional/rpc_net.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/rpc_openrpc.py",
   "add": 2,
   "del": 2
  },
  {
   "path": "test/functional/rpc_psbt.py",
   "add": 40,
   "del": 38
  },
  {
   "path": "test/functional/rpc_rawtransaction.py",
   "add": 9,
   "del": 7
  },
  {
   "path": "test/functional/rpc_scanblocks.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/rpc_scantxoutset.py",
   "add": 4,
   "del": 4
  },
  {
   "path": "test/functional/rpc_signer.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/rpc_signrawtransactionwithkey.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/rpc_validateaddress.py",
   "add": 3,
   "del": 3
  },
  {
   "path": "test/functional/test_framework/test_framework.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/test_framework/util.py",
   "add": 10,
   "del": 1
  },
  {
   "path": "test/functional/test_framework/wallet.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/tool_wallet.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_abandonconflict.py",
   "add": 7,
   "del": 5
  },
  {
   "path": "test/functional/wallet_address_types.py",
   "add": 3,
   "del": 2
  },
  {
   "path": "test/functional/wallet_anchor.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_ancient_migration.py",
   "add": 9,
   "del": 7
  },
  {
   "path": "test/functional/wallet_assumeutxo.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/wallet_avoidreuse.py",
   "add": 10,
   "del": 8
  },
  {
   "path": "test/functional/wallet_backwards_compatibility.py",
   "add": 9,
   "del": 7
  },
  {
   "path": "test/functional/wallet_balance.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/wallet_basic.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/wallet_blank.py",
   "add": 7,
   "del": 6
  },
  {
   "path": "test/functional/wallet_bumpfee.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/wallet_createwallet.py",
   "add": 4,
   "del": 3
  },
  {
   "path": "test/functional/wallet_createwalletdescriptor.py",
   "add": 9,
   "del": 7
  },
  {
   "path": "test/functional/wallet_deprecated_rbf.py",
   "add": 2,
   "del": 2
  },
  {
   "path": "test/functional/wallet_derivehdkey.py",
   "add": 3,
   "del": 2
  },
  {
   "path": "test/functional/wallet_descriptor.py",
   "add": 6,
   "del": 4
  },
  {
   "path": "test/functional/wallet_disable.py",
   "add": 3,
   "del": 3
  },
  {
   "path": "test/functional/wallet_encryption.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_exported_watchonly.py",
   "add": 11,
   "del": 9
  },
  {
   "path": "test/functional/wallet_fundrawtransaction.py",
   "add": 7,
   "del": 6
  },
  {
   "path": "test/functional/wallet_gethdkeys.py",
   "add": 19,
   "del": 17
  },
  {
   "path": "test/functional/wallet_hd.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_importdescriptors.py",
   "add": 23,
   "del": 21
  },
  {
   "path": "test/functional/wallet_importprunedfunds.py",
   "add": 9,
   "del": 7
  },
  {
   "path": "test/functional/wallet_keypool.py",
   "add": 8,
   "del": 7
  },
  {
   "path": "test/functional/wallet_labels.py",
   "add": 6,
   "del": 6
  },
  {
   "path": "test/functional/wallet_listreceivedby.py",
   "add": 3,
   "del": 2
  },
  {
   "path": "test/functional/wallet_listsinceblock.py",
   "add": 6,
   "del": 4
  },
  {
   "path": "test/functional/wallet_listtransactions.py",
   "add": 9,
   "del": 7
  },
  {
   "path": "test/functional/wallet_migration.py",
   "add": 95,
   "del": 93
  },
  {
   "path": "test/functional/wallet_miniscript.py",
   "add": 5,
   "del": 5
  },
  {
   "path": "test/functional/wallet_miniscript_decaying_multisig_descriptor_psbt.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_multiwallet.py",
   "add": 7,
   "del": 5
  },
  {
   "path": "test/functional/wallet_musig.py",
   "add": 10,
   "del": 7
  },
  {
   "path": "test/functional/wallet_orphanedreward.py",
   "add": 4,
   "del": 4
  },
  {
   "path": "test/functional/wallet_reorgsrestore.py",
   "add": 12,
   "del": 10
  },
  {
   "path": "test/functional/wallet_resendwallettransactions.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_send.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/wallet_sendall.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_signer.py",
   "add": 13,
   "del": 11
  },
  {
   "path": "test/functional/wallet_signrawtransactionwithwallet.py",
   "add": 5,
   "del": 4
  },
  {
   "path": "test/functional/wallet_simulaterawtx.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_transactiontime_rescan.py",
   "add": 6,
   "del": 4
  },
  {
   "path": "test/functional/wallet_txn_clone.py",
   "add": 2,
   "del": 1
  },
  {
   "path": "test/functional/wallet_txn_doublespend.py",
   "add": 4,
   "del": 2
  }
 ],
 "test_lines": 1148,
 "git": {
  "head": "01ff43d926b27d224e7b1ea1ba97a8d7b241a59c",
  "head_matches_backup": true,
  "base": "51ddab532cb38213e2258c24c492bc8a392ffc90",
  "commits": [
   {
    "sha": "486d0027e5",
    "subject": "qa: Add assert_true() / assert_false()",
    "files": 1,
    "add": 9,
    "del": 0
   },
   {
    "sha": "acef9ecdae",
    "subject": "qa: Fix weird case of 3-arg assert_equal() ahead of scripted diff",
    "files": 1,
    "add": 3,
    "del": 1
   },
   {
    "sha": "f27214f16d",
    "subject": "qa: Fixup imports ahead of scripted diff",
    "files": 92,
    "add": 150,
    "del": 35
   },
   {
    "sha": "bd1776c028",
    "subject": "scripted-diff: Replace assert_equals([..., ]True/False[, ...]) with assert_true/assert_false",
    "files": 93,
    "add": 475,
    "del": 475
   },
   {
    "sha": "01ff43d926",
    "subject": "qa: Remove no longer used assert_equals imports",
    "files": 2,
    "add": 2,
    "del": 2
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "552993d89264a5b5",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}