{
  "slug": "ddrescue-image-provenance",
  "title": "ddrescue image provenance: twelve controlled cases",
  "summary": "Complete maps, stale output bytes, approximate map reconstruction and identical images with different acquisition histories.",
  "published": "2026-10-18",
  "updated": "2026-10-18",
  "method": "Eight rescue/resume cases, three approximate-map cases and one post-copy modification on a known 4096-byte fixture. Read errors are simulated with --test-mode.",
  "limits": [
    "Regular files only; software-simulated read errors.",
    "One upstream version and build; no hardware recovery rates, power-loss or timing claims.",
    "Map '+' describes rescue bookkeeping, not a digest comparison with the source.",
    "Reused sparse output intentionally violates the documented empty-or-zeroed destination precondition.",
    "Matching-byte totals apply to fixtures with whole-sector differences, not a generic byte-difference calculation."
  ],
  "license": "Hesela-authored code, observations and derived CSV: MIT. GNU source and documentation retain their licenses and are not redistributed.",
  "licenseUrl": "https://hesela.dev/research/ddrescue-provenance/LICENSE",
  "downloadPath": "/data/ddrescue-image-provenance.csv",
  "rawPath": "/research/ddrescue-provenance/results.json",
  "codePath": "/research/ddrescue-provenance/observe.py",
  "testsPath": "/research/ddrescue-provenance/test_observe.py",
  "generatorPath": "/research/ddrescue-provenance/build_publication.py",
  "validationTestsPath": "/research/ddrescue-provenance/test_publication.py",
  "replayPath": "/research/ddrescue-provenance/replay-20261018.json",
  "humanPage": "https://hesela.com/analyses/ddrescue-image-provenance/",
  "rowCount": 12,
  "columns": [
    {
      "name": "case",
      "type": "string",
      "description": "Stable scenario ID, not an independent fleet observation."
    },
    {
      "name": "mode",
      "type": "string",
      "description": "Rescue, resume, approximate map generation or post-copy modification."
    },
    {
      "name": "source_bytes",
      "type": "integer",
      "description": "Known fixture extent in bytes."
    },
    {
      "name": "finished_bytes",
      "type": "integer",
      "description": "Bytes in map ranges marked +, not independently verified image bytes."
    },
    {
      "name": "matching_source_bytes",
      "type": "integer",
      "description": "Bytes equal to the fixture; differences in these cases occupy whole sectors."
    },
    {
      "name": "operation_status",
      "type": "integer",
      "description": "Operation exit status; modification is a fixture action, not ddrescue."
    },
    {
      "name": "done_status",
      "type": "integer",
      "description": "ddrescuelog --done-status over the full map domain."
    },
    {
      "name": "first_sector_done_status",
      "type": "integer",
      "description": "The same check restricted to the first 512 bytes."
    },
    {
      "name": "image_sha256",
      "type": "string",
      "description": "Output digest, not source authentication or acquisition history."
    }
  ],
  "rows": [
    {
      "case": "fresh-bad-data",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 3584,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 1,
      "first_sector_done_status": 0,
      "image_sha256": "f018401cb65be53daa0483a7581ccee9d5b5ac616fe77c5367995af50954f2cc"
    },
    {
      "case": "reused-bad-data",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 3584,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 1,
      "first_sector_done_status": 0,
      "image_sha256": "a4c7d3691b80efb7b0373c42ee61f269d612a9be4256bbc8858a8f0758d05491"
    },
    {
      "case": "fresh-bad-zero",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 3584,
      "matching_source_bytes": 4096,
      "operation_status": 0,
      "done_status": 1,
      "first_sector_done_status": 0,
      "image_sha256": "2d52d2f58e027b88b7f5487af54413141f1ebe868b9847c3286daeec99f99a2d"
    },
    {
      "case": "fresh-healthy",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 4096,
      "matching_source_bytes": 4096,
      "operation_status": 0,
      "done_status": 0,
      "first_sector_done_status": 0,
      "image_sha256": "2d52d2f58e027b88b7f5487af54413141f1ebe868b9847c3286daeec99f99a2d"
    },
    {
      "case": "sparse-fresh-healthy",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 4096,
      "matching_source_bytes": 4096,
      "operation_status": 0,
      "done_status": 0,
      "first_sector_done_status": 0,
      "image_sha256": "2d52d2f58e027b88b7f5487af54413141f1ebe868b9847c3286daeec99f99a2d"
    },
    {
      "case": "sparse-reused-healthy",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 4096,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 0,
      "first_sector_done_status": 0,
      "image_sha256": "6d10c447de8e64ce6b2ac6c1a485af0825b089c479d15d91d06426f4b6632eec"
    },
    {
      "case": "sparse-reused-bad-data",
      "mode": "rescue",
      "source_bytes": 4096,
      "finished_bytes": 3584,
      "matching_source_bytes": 3072,
      "operation_status": 0,
      "done_status": 1,
      "first_sector_done_status": 0,
      "image_sha256": "a6b477d42e7e818375085ae831f7db19ca2bc565ecbb396bf00de657c32ffe71"
    },
    {
      "case": "resume-sparse-reused",
      "mode": "resume",
      "source_bytes": 4096,
      "finished_bytes": 4096,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 0,
      "first_sector_done_status": 0,
      "image_sha256": "6d10c447de8e64ce6b2ac6c1a485af0825b089c479d15d91d06426f4b6632eec"
    },
    {
      "case": "generated-fresh-bad-data",
      "mode": "generate",
      "source_bytes": 4096,
      "finished_bytes": 3072,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 1,
      "first_sector_done_status": 0,
      "image_sha256": "f018401cb65be53daa0483a7581ccee9d5b5ac616fe77c5367995af50954f2cc"
    },
    {
      "case": "generated-reused-bad-data",
      "mode": "generate",
      "source_bytes": 4096,
      "finished_bytes": 3584,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 1,
      "first_sector_done_status": 0,
      "image_sha256": "a4c7d3691b80efb7b0373c42ee61f269d612a9be4256bbc8858a8f0758d05491"
    },
    {
      "case": "generated-sparse-reused-bad-data",
      "mode": "generate",
      "source_bytes": 4096,
      "finished_bytes": 4096,
      "matching_source_bytes": 3072,
      "operation_status": 0,
      "done_status": 0,
      "first_sector_done_status": 0,
      "image_sha256": "a6b477d42e7e818375085ae831f7db19ca2bc565ecbb396bf00de657c32ffe71"
    },
    {
      "case": "modified-after-completion",
      "mode": "post-copy-modification",
      "source_bytes": 4096,
      "finished_bytes": 4096,
      "matching_source_bytes": 3584,
      "operation_status": 0,
      "done_status": 0,
      "first_sector_done_status": 0,
      "image_sha256": "999474e2a3043de78c92b81091a9e2dabc55f729e462389793055817583943cf"
    }
  ],
  "environment": {
    "python": "3.12.14",
    "kernel": "6.18.55",
    "system": "Linux",
    "machine": "x86_64",
    "versions": [
      {
        "argv": [
          "ddrescue",
          "--version"
        ],
        "returncode": 0,
        "stdout": "GNU ddrescue 1.30\nCopyright (C) 2026 Antonio Diaz Diaz.\nLicense GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n",
        "stderr": ""
      },
      {
        "argv": [
          "ddrescuelog",
          "--version"
        ],
        "returncode": 0,
        "stdout": "GNU ddrescuelog 1.30\nCopyright (C) 2026 Antonio Diaz Diaz.\nLicense GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n",
        "stderr": ""
      }
    ],
    "executableSha256": {
      "ddrescue": "a7eea3ce9cc7f1fd1fc7b8aae1e38002cb4097a2b18a6c5ef8e6bfa0544e468c",
      "ddrescuelog": "f407cd8892bdfb21335616416acad85163840e225b47404f42f37ff6b8e672dc"
    }
  },
  "replayEnvironment": {
    "python": "3.12.3",
    "kernel": "6.8.0-146-generic",
    "system": "Linux",
    "machine": "x86_64",
    "versions": [
      {
        "argv": [
          "ddrescue",
          "--version"
        ],
        "returncode": 0,
        "stdout": "GNU ddrescue 1.30\nCopyright (C) 2026 Antonio Diaz Diaz.\nLicense GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n",
        "stderr": ""
      },
      {
        "argv": [
          "ddrescuelog",
          "--version"
        ],
        "returncode": 0,
        "stdout": "GNU ddrescuelog 1.30\nCopyright (C) 2026 Antonio Diaz Diaz.\nLicense GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n",
        "stderr": ""
      }
    ],
    "executableSha256": {
      "ddrescue": "b8f1bc06e4478e91f01e46105fdc7ede56cda3f8b3864b6cb3509fd8e1aa8d78",
      "ddrescuelog": "b68d1d669869d7bda69118e3cc1709e8a7d52f733c61fa6f233d7b4df216cd15"
    }
  },
  "generatedAt": "2026-10-18T05:23:15.836662+00:00",
  "replayedAt": "2026-10-18T09:23:46.198610+00:00",
  "citations": [
    {
      "id": "gnu",
      "title": "GNU ddrescue 1.30 manual: sparse output, generate mode and ddrescuelog",
      "url": "https://www.gnu.org/software/ddrescue/manual/ddrescue_manual.html",
      "accessed": "2026-10-18"
    },
    {
      "id": "source",
      "title": "GNU ddrescue 1.30 source release: rescuebook.cc and genbook.cc",
      "url": "https://ftp.gnu.org/gnu/ddrescue/ddrescue-1.30.tar.lz",
      "accessed": "2026-10-18"
    }
  ],
  "sha256": {
    "observe.py": "2b80ed1ae80fc1209fb528493d31e618efb64b1bfd71b9fe2b61550362189432",
    "test_observe.py": "cc15359b7627212c4645ea8cef273e448518e7b2e422b9d95f0c608929cd800b",
    "results.json": "6b1f2c4d85bb9371aacd5c7cbbbaef8a29d0e16cf094d5bccbd52097cdd2fa7f",
    "replay-20261018.json": "bbd37cd580c4cf0e6f4550a13e9471f247df225af53abf535b5bdf957364864d",
    "sources.json": "96d2ef6144aade334a0b90e1e65392db2affcff0a4970ff4e4d91922942c97ec",
    "claims.json": "2d23d3f3b9e12eeeba61e4674cef3d20b6cfc9013941dfb2194d735fc3bc8559",
    "LICENSE": "00352d2e976d0efed2807e48d0d7b1196253dcd56975c4cddd4782c286de0bf9",
    "report.md": "ad3b079adbfb45a342b88fda56b6aadfc44c4e4031bcd066a378620bb37fe72c",
    "build_publication.py": "ea5046661a2ba503e076e7fb3ecd1952762864761c1d51e8489c372f4e7798da",
    "test_publication.py": "a6ae077d43d589be7b4f4d6086e0d48dd0b7f4adcf4a0b0ccf1f78761162a3b6",
    "build_report.py": "816913b50752b5a558d9f05efaa6f47f579a6d652c6735246049e20c91c5aefd",
    "report.template.md": "f845dee9731af2aff0bdc9bd4ec29d6540a1d950484797efef06f84d9bf1d8b8"
  },
  "csvSha256": "8c32e1eaeefc452341ea2902bf1c54a0dd28b09c0bf737a60eff20e8d2cbeea0"
}
