FA-1116 / Workflow orchestration / Open access
Start a durable workflow execution: A child starts after its parent was cancelled · case 01
The workflow start operation is admitted even though a child starts after its parent was cancelled.
ROOT CAUSE
The admission path omits the parent live invariant while validating the other operation preconditions.
VERIFIED REPAIR
Require r['parent_live'] == 'running' together with every other stated precondition before accepting the operation.
Unsuccessful approach: Adding the parent live check repairs the reported defect, but replacing the adjacent start deadline check loses that independent invariant.
Case contract
Return a Boolean admission decision for start a durable workflow execution. The record r must satisfy all of: r['execution_unique'][0] not in r['execution_unique'][1]; r['version_available'][0] in r['version_available'][1]; set(r['input_required'][0]) <= set(r['input_required'][1]); r['parent_live'] == 'running'; r['start_deadline'][0] < r['start_deadline'][1]. Extra tracing fields are ignored; validation does not mutate the record.
Why this case matters
A deterministic local contract for workflow orchestration. Each negative fixture violates exactly one invariant. No transport timing, persistence, cryptographic verification, or full protocol implementation is claimed.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(r):
return (r['execution_unique'][0] not in r['execution_unique'][1]) and (r['version_available'][0] in r['version_available'][1]) and (set(r['input_required'][0]) <= set(r['input_required'][1])) and (r['start_deadline'][0] < r['start_deadline'][1])
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r = {'execution_unique': ['e2', ['e1']], 'version_available': [3, [2, 3]], 'input_required': [['order'], ['order', 'note']], 'parent_live': 'running', 'start_deadline': [10, 11]}
check('valid operation', solve(r), True)
check('A duplicate start creates a second active execution', solve(dict(r, **{'execution_unique': ['e1', ['e1']]})), False)
check('The workflow starts on an unavailable definition version', solve(dict(r, **{'version_available': [4, [2, 3]]})), False)
check('A workflow starts without its required input fields', solve(dict(r, **{'input_required': [['order'], ['note']]})), False)
check('A child starts after its parent was cancelled', solve(dict(r, **{'parent_live': 'cancelled'})), False)
check('A deferred start begins beyond the workflow start deadline', solve(dict(r, **{'start_deadline': [11, 11]})), False)
check('unrelated tracing metadata', solve(dict(r, trace='run-'+str(N))), True)
check('repeat validation is pure', solve(r), True)
invalid = {'execution_unique': ['e1', ['e1']], 'version_available': [4, [2, 3]], 'input_required': [['order'], ['note']], 'parent_live': 'cancelled', 'start_deadline': [11, 11]}
keys = list(invalid)
pair = {keys[N % len(keys)]: invalid[keys[N % len(keys)]], keys[(N+1) % len(keys)]: invalid[keys[(N+1) % len(keys)]]}
check('two independent violations in variant', solve(dict(r, **pair)), False)
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 |
|---|---|---|---|
| valid operation | True | True | Passed |
| A duplicate start creates a second active execution | False | False | Passed |
| The workflow starts on an unavailable definition version | False | False | Passed |
| A workflow starts without its required input fields | False | False | Passed |
| A child starts after its parent was cancelled | True | False | Failed |
| A deferred start begins beyond the workflow start deadline | False | False | Passed |
| unrelated tracing metadata | True | True | Passed |
| repeat validation is pure | True | True | Passed |
| two independent violations in variant | False | False | Passed |
SHA-256 / d6222aa8a215fa0cf2ee08564385e8793b5247276a877c38e6c6495ae495c3d8
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(r):
return (r['execution_unique'][0] not in r['execution_unique'][1]) and (r['version_available'][0] in r['version_available'][1]) and (set(r['input_required'][0]) <= set(r['input_required'][1])) and (r['parent_live'] == 'running')
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r = {'execution_unique': ['e2', ['e1']], 'version_available': [3, [2, 3]], 'input_required': [['order'], ['order', 'note']], 'parent_live': 'running', 'start_deadline': [10, 11]}
check('valid operation', solve(r), True)
check('A duplicate start creates a second active execution', solve(dict(r, **{'execution_unique': ['e1', ['e1']]})), False)
check('The workflow starts on an unavailable definition version', solve(dict(r, **{'version_available': [4, [2, 3]]})), False)
check('A workflow starts without its required input fields', solve(dict(r, **{'input_required': [['order'], ['note']]})), False)
check('A child starts after its parent was cancelled', solve(dict(r, **{'parent_live': 'cancelled'})), False)
check('A deferred start begins beyond the workflow start deadline', solve(dict(r, **{'start_deadline': [11, 11]})), False)
check('unrelated tracing metadata', solve(dict(r, trace='run-'+str(N))), True)
check('repeat validation is pure', solve(r), True)
invalid = {'execution_unique': ['e1', ['e1']], 'version_available': [4, [2, 3]], 'input_required': [['order'], ['note']], 'parent_live': 'cancelled', 'start_deadline': [11, 11]}
keys = list(invalid)
pair = {keys[N % len(keys)]: invalid[keys[N % len(keys)]], keys[(N+1) % len(keys)]: invalid[keys[(N+1) % len(keys)]]}
check('two independent violations in variant', solve(dict(r, **pair)), False)
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 |
|---|---|---|---|
| valid operation | True | True | Passed |
| A duplicate start creates a second active execution | False | False | Passed |
| The workflow starts on an unavailable definition version | False | False | Passed |
| A workflow starts without its required input fields | False | False | Passed |
| A child starts after its parent was cancelled | False | False | Passed |
| A deferred start begins beyond the workflow start deadline | True | False | Failed |
| unrelated tracing metadata | True | True | Passed |
| repeat validation is pure | True | True | Passed |
| two independent violations in variant | False | False | Passed |
SHA-256 / 28ea0ee976102d6eb3e4d61772928b08361f235b2c6eeeeaa3d1aeda18b987d0
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(r):
return (r['execution_unique'][0] not in r['execution_unique'][1]) and (r['version_available'][0] in r['version_available'][1]) and (set(r['input_required'][0]) <= set(r['input_required'][1])) and (r['parent_live'] == 'running') and (r['start_deadline'][0] < r['start_deadline'][1])
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r = {'execution_unique': ['e2', ['e1']], 'version_available': [3, [2, 3]], 'input_required': [['order'], ['order', 'note']], 'parent_live': 'running', 'start_deadline': [10, 11]}
check('valid operation', solve(r), True)
check('A duplicate start creates a second active execution', solve(dict(r, **{'execution_unique': ['e1', ['e1']]})), False)
check('The workflow starts on an unavailable definition version', solve(dict(r, **{'version_available': [4, [2, 3]]})), False)
check('A workflow starts without its required input fields', solve(dict(r, **{'input_required': [['order'], ['note']]})), False)
check('A child starts after its parent was cancelled', solve(dict(r, **{'parent_live': 'cancelled'})), False)
check('A deferred start begins beyond the workflow start deadline', solve(dict(r, **{'start_deadline': [11, 11]})), False)
check('unrelated tracing metadata', solve(dict(r, trace='run-'+str(N))), True)
check('repeat validation is pure', solve(r), True)
invalid = {'execution_unique': ['e1', ['e1']], 'version_available': [4, [2, 3]], 'input_required': [['order'], ['note']], 'parent_live': 'cancelled', 'start_deadline': [11, 11]}
keys = list(invalid)
pair = {keys[N % len(keys)]: invalid[keys[N % len(keys)]], keys[(N+1) % len(keys)]: invalid[keys[(N+1) % len(keys)]]}
check('two independent violations in variant', solve(dict(r, **pair)), False)
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 |
|---|---|---|---|
| valid operation | True | True | Passed |
| A duplicate start creates a second active execution | False | False | Passed |
| The workflow starts on an unavailable definition version | False | False | Passed |
| A workflow starts without its required input fields | False | False | Passed |
| A child starts after its parent was cancelled | False | False | Passed |
| A deferred start begins beyond the workflow start deadline | False | False | Passed |
| unrelated tracing metadata | True | True | Passed |
| repeat validation is pure | True | True | Passed |
| two independent violations in variant | False | False | Passed |
SHA-256 / bb4b4e3f7f304e889582731d42ea6d7fa9392e718de3751d4fe0d5fe209f2ac2
Verification & scope
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:36:58.743675+00:00.
Case digest / e2c89682c68a4c03bbf311c86802d9f58cbddd52360d2084f913fe32b8133ce2