FA-11936 / Scientific pipeline provenance / Open access
A reprocessed artifact retains the previous processing provenance · case 01
A reprocessed artifact retains the previous processing provenance.
ROOT CAUSE
A new artifact inherits its parent processing history without recording the new run.
VERIFIED REPAIR
Append the new run to inherited ordered history without mutating the input.
Unsuccessful approach: Replacing history with the latest run discards earlier processing.
Case contract
Return inherited ordered run IDs followed by the current run ID; repeated run IDs represent separate executions and are retained.
Why this case matters
A deterministic offline model of scientific workflow bookkeeping; the fixtures test provenance contracts without modeling instruments or biological inference.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(history, run):
return list(history)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r='run'+str(N)
check('reprocessing records both runs', solve(['raw','filter'], r), ['raw','filter',r])
check('initial processing', solve([], r), [r])
check('same run repeated', solve([r], r), [r,r])
check('one previous run', solve(['raw'], r), ['raw',r])
check('order of ancestors retained', solve(['z','a'], r), ['z','a',r])
h=['raw']
solve(h,r)
check('parent provenance immutable', h, ['raw'])
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| reprocessing records both runs | ['raw', 'filter'] | ['raw', 'filter', 'run1'] | Failed |
| initial processing | [] | ['run1'] | Failed |
| same run repeated | ['run1'] | ['run1', 'run1'] | Failed |
| one previous run | ['raw'] | ['raw', 'run1'] | Failed |
| order of ancestors retained | ['z', 'a'] | ['z', 'a', 'run1'] | Failed |
| parent provenance immutable | ['raw'] | ['raw'] | Passed |
SHA-256 / eaae151133dff2d21be7cc30d1b7e90c29e0cf53a61b26716b56cc8c68fd107b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(history, run):
return [run]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r='run'+str(N)
check('reprocessing records both runs', solve(['raw','filter'], r), ['raw','filter',r])
check('initial processing', solve([], r), [r])
check('same run repeated', solve([r], r), [r,r])
check('one previous run', solve(['raw'], r), ['raw',r])
check('order of ancestors retained', solve(['z','a'], r), ['z','a',r])
h=['raw']
solve(h,r)
check('parent provenance immutable', h, ['raw'])
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| reprocessing records both runs | ['run1'] | ['raw', 'filter', 'run1'] | Failed |
| initial processing | ['run1'] | ['run1'] | Passed |
| same run repeated | ['run1'] | ['run1', 'run1'] | Failed |
| one previous run | ['run1'] | ['raw', 'run1'] | Failed |
| order of ancestors retained | ['run1'] | ['z', 'a', 'run1'] | Failed |
| parent provenance immutable | ['raw'] | ['raw'] | Passed |
SHA-256 / 0b3685ec5ba00cb80b8b40e38e4e89cb3993c35655ab87e3b9f21259e384addd
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(history, run):
return list(history)+[run]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r='run'+str(N)
check('reprocessing records both runs', solve(['raw','filter'], r), ['raw','filter',r])
check('initial processing', solve([], r), [r])
check('same run repeated', solve([r], r), [r,r])
check('one previous run', solve(['raw'], r), ['raw',r])
check('order of ancestors retained', solve(['z','a'], r), ['z','a',r])
h=['raw']
solve(h,r)
check('parent provenance immutable', h, ['raw'])
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| reprocessing records both runs | ['raw', 'filter', 'run1'] | ['raw', 'filter', 'run1'] | Passed |
| initial processing | ['run1'] | ['run1'] | Passed |
| same run repeated | ['run1', 'run1'] | ['run1', 'run1'] | Passed |
| one previous run | ['raw', 'run1'] | ['raw', 'run1'] | Passed |
| order of ancestors retained | ['z', 'a', 'run1'] | ['z', 'a', 'run1'] | Passed |
| parent provenance immutable | ['raw'] | ['raw'] | Passed |
SHA-256 / 221837544f04a2e671edd34a3a6db4589becf870c9b3a36c55321185c9963bb9
Verification & scope
In-memory symbolic records only; no instrument, assay, or production workflow validation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:38:52.365213+00:00.
Case digest / d4842024bd238f914813f8b71de8638e67c5054f2b982a373eaad8972faa5f3a