{
 "number": 35809,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35809",
 "title": "contrib: add deterministic fuzz coverage mode",
 "author": "HowHsu",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-07-26T14:17:03Z",
 "updated_at": "2026-09-10T15:57:46Z",
 "age_days": 53,
 "draft": false,
 "labels": [
  "Scripts and tools"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "754a9e908ff828341d8eee657584b8ebd31f58e3",
 "head_ref": "det-fuzz-cov-param",
 "head_repo": "HowHsu/bitcoin",
 "head_history": [
  {
   "t": "2026-08-24T11:56:38Z",
   "sha": "635b1cccb6baf5eb9b9aaf0aa4e576507e52dd54"
  },
  {
   "t": "2026-09-03T14:47:41Z",
   "sha": "754a9e908ff828341d8eee657584b8ebd31f58e3"
  }
 ],
 "additions": 83,
 "deletions": 43,
 "changed_files": 2,
 "commit_count": 1,
 "size_bucket": "M",
 "mergeable_state": "unknown",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "ack": [
     {
      "login": "Crypt-iQ",
      "url": "https://github.com/bitcoin/bitcoin/pull/35809#pullrequestreview-5116071804"
     },
     {
      "login": "marcofleon",
      "url": "https://github.com/bitcoin/bitcoin/pull/35809#pullrequestreview-5169395595"
     }
    ],
    "stale_ack": [
     {
      "login": "jeanpablojp",
      "url": "https://github.com/bitcoin/bitcoin/pull/35809#issuecomment-5334737207"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35608,
     "title": "contrib: Skip llvm-cov rendering for deterministic fuzz inputs",
     "author": "HowHsu"
    }
   ]
  }
 },
 "acks_parsed": {
  "Crypt-iQ": {
   "kind": "ack",
   "hash": "754a9e908ff828341d8eee657584b8ebd31f58e3",
   "t": "2026-09-04T19:06:11Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 1,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 1,
  "changes_requested": 0,
  "distinct_reviewers": [
   "Crypt-iQ",
   "fanquake",
   "jeanpablojp",
   "maflcko",
   "marcofleon"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "unknown",
  "last_author_activity": "2026-09-03T14:47:41Z",
  "last_reviewer_activity": "2026-09-10T15:57:42Z",
  "last_reviewer": "marcofleon",
  "author_silent_days": 14,
  "waiting_on_author_days": 7,
  "days_since_update": 7
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": [
   35608
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "contrib/devtools/README.md",
  "contrib/devtools/deterministic-fuzz-coverage/src/main.rs"
 ],
 "body": "Adds an optional integer `coverage_check` argument to `deterministic-fuzz-coverage`:\n\n- `0`: run both checks, preserving the current default behavior\n- `1`: only check each corpus input individually\n- `2`: only check all corpus inputs in one process\n\nThis makes it easier to isolate per-input nondeterminism from cross-input state leakage.\nGood for debugging.",
 "commits": [
  {
   "sha": "754a9e908ff828341d8eee657584b8ebd31f58e3",
   "date": "2026-09-03T14:46:49Z",
   "message": "contrib: add deterministic fuzz coverage mode\n\nAdd an optional coverage_check argument to deterministic-fuzz-coverage.\nThe `both` mode runs both checks and preserves the current default\nbehavior. The `single` mode checks each corpus input individually.\nThe `combined` mode checks all corpus inputs in a single process.\n\nThis makes it easier to distinguish per-input nondeterminism from\ncross-input state leakage. Good for debugging.\n\nCo-authored-by: maflcko <6399679+maflcko@users.noreply.github.com>"
  }
 ],
 "timeline": [
  {
   "t": "2026-08-13T08:02:47Z",
   "kind": "comment",
   "who": "HowHsu",
   "assoc": "CONTRIBUTOR",
   "text": "Hi @maflcko , any chacne to have a look at this one when you're available.\nThanks."
  },
  {
   "t": "2026-08-18T22:16:16Z",
   "kind": "comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "text": "tACK e01ca9bacdeb860291b1824cac7fb099a3b41111\n\nBuilt the tool and ran all three modes against an instrumented binary I put together here, all green, and the check catches nondeterminism on both paths. Mode 0 came out identical to master.\n\nSilly nit: could the motivation go into the commit message?"
  },
  {
   "t": "2026-08-24T11:56:38Z",
   "kind": "force_push",
   "who": "HowHsu",
   "commit": "635b1cccb6baf5eb9b9aaf0aa4e576507e52dd54"
  },
  {
   "t": "2026-08-24T11:57:17Z",
   "kind": "comment",
   "who": "HowHsu",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nSorry for the delay, updated."
  },
  {
   "t": "2026-09-01T17:12:33Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "contrib/devtools/deterministic-fuzz-coverage/src/main.rs",
   "commit": "635b1cccb6baf5eb9b9aaf0aa4e576507e52dd54",
   "in_reply_to": null,
   "text": "Would be cleaner to use properly named strings for this enum? E.g:\n\n```rs\n            \"both\" => Ok(Self::Both),\n            \"single\" => Ok(Self::IndividualInputs),\n            \"combined\" => Ok(Self::AllInputs),\n            other => Err(exit_help(&format!(\n                \"Invalid coverage check mode '{other}'. Expected 'both', 'single', or 'combined'\"\n            ))),\n```\n\nPossibly this could just be a single bool without any extra class and with proper named args:\n\n```rust\nlet mut check_individual = true; // default is \"both\"\n\n// skip the pos args (everything after is a named arg)\nfor arg in env::args().skip(5) {\n   if let Some(value) = arg.strip_prefix(\"--mode=\") {\n        check_individual = match value {\n            \"both\" => true,\n            \"combined\" => false,\n            other => return Err(help(&format!(\n                \"Invalid mode '{other}'. Expected 'both' or 'combined'\"\n            ))),\n        };\n    }else {\n        return Err(help(&format!(\"Too many args, or unknown named arg: {arg}\")));\n    }\n}\n```\n\nThe rationale being that there should be no reason to skip the full combined check, only the expensive single check. Otherwise, two boolean flags are still simpler than a full enum class for this?"
  },
  {
   "t": "2026-09-01T17:15:59Z",
   "kind": "review",
   "who": "maflcko",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "635b1cccb6baf5eb9b9aaf0aa4e576507e52dd54",
   "text": "Seems fine, but would be good to use named args at some point \ud83d\ude05"
  },
  {
   "t": "2026-09-02T08:53:37Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "cc @marcofleon @Crypt-iQ"
  },
  {
   "t": "2026-09-03T14:01:45Z",
   "kind": "review_comment",
   "who": "HowHsu",
   "assoc": "CONTRIBUTOR",
   "path": "contrib/devtools/deterministic-fuzz-coverage/src/main.rs",
   "commit": "635b1cccb6baf5eb9b9aaf0aa4e576507e52dd54",
   "in_reply_to": 3906550539,
   "text": "[quoted text omitted]\n\nThe motivation to propose this PR is when I fixed a coverage issue, I run the tool to verify if it worked, and it's really time-consuming. Forgot which target I used, but I recall the `combined run` itself is time-consuming too, let's go wtih the former one?\n\n```\n            \"both\" => Ok(Self::Both),\n            \"single\" => Ok(Self::IndividualInputs),\n            \"combined\" => Ok(Self::AllInputs),\n            other => Err(exit_help(&format!(\n                \"Invalid coverage check mode '{other}'. Expected 'both', 'single', or 'combined'\"\n            ))),\n```"
  },
  {
   "t": "2026-09-03T14:47:41Z",
   "kind": "force_push",
   "who": "HowHsu",
   "commit": "754a9e908ff828341d8eee657584b8ebd31f58e3"
  },
  {
   "t": "2026-09-04T17:31:35Z",
   "kind": "review_comment",
   "who": "Crypt-iQ",
   "assoc": "MEMBER",
   "path": "contrib/devtools/README.md",
   "commit": "754a9e908ff828341d8eee657584b8ebd31f58e3",
   "in_reply_to": null,
   "text": "nit: could be more descriptive for somebody reading this and say: `both runs each input individually and all inputs in one go`, or put it at the end after `combined`"
  },
  {
   "t": "2026-09-04T19:06:11Z",
   "kind": "review",
   "who": "Crypt-iQ",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "754a9e908ff828341d8eee657584b8ebd31f58e3",
   "text": "crACK 754a9e908ff828341d8eee657584b8ebd31f58e3"
  },
  {
   "t": "2026-09-10T15:57:42Z",
   "kind": "review",
   "who": "marcofleon",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "754a9e908ff828341d8eee657584b8ebd31f58e3",
   "text": "tACK 754a9e908ff828341d8eee657584b8ebd31f58e3"
  }
 ],
 "labels_log": [
  {
   "t": "2026-07-26T14:17:06Z",
   "action": "labeled",
   "label": "Scripts and tools",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 3507,
 "text_tokens_estimate": 876,
 "changed_paths": [
  "contrib/devtools/README.md",
  "contrib/devtools/deterministic-fuzz-coverage/src/main.rs"
 ],
 "files": [
  {
   "path": "contrib/devtools/README.md",
   "add": 5,
   "del": 1
  },
  {
   "path": "contrib/devtools/deterministic-fuzz-coverage/src/main.rs",
   "add": 78,
   "del": 42
  }
 ],
 "test_lines": 126,
 "git": {
  "head": "754a9e908ff828341d8eee657584b8ebd31f58e3",
  "head_matches_backup": true,
  "base": "e34b8d5a7dcd45e4faa3bb5fdeae64bf049037f6",
  "commits": [
   {
    "sha": "754a9e908f",
    "subject": "contrib: add deterministic fuzz coverage mode",
    "files": 2,
    "add": 83,
    "del": 43
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "50cd88d3a53b5cd3",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}