FA-9146 / Build systems / Open access
Build prerequisite closure: Undeclared leaf targets disappear · case 01
Undeclared leaf targets disappear.
ROOT CAUSE
The implementation substitutes seen.update([node] if node in edges else []) if node not in edges: continue for seen.add(node), so undeclared leaf targets disappear.
VERIFIED REPAIR
Keep names even if no adjacency declaration exists.
Unsuccessful approach: The attempted repair substitutes seen.add(node) if node in edges: continue. Fixture 3 still yields ['a'] instead of ['a', 'b'].
Case contract
Return sorted unique reachable target names including roots. Traverse normal prerequisites, exclude order-only prerequisites, retain unknown leaves, and stop cycles.
Why this case matters
An offline model of build prerequisite closure, suitable for testing build and release tooling without external services.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(roots, edges):
seen = set()
stack = list(roots)
while stack:
node = stack.pop()
if node in seen:
continue
seen.update([node] if node in edges else [])
if node not in edges:
continue
stack.extend(dep for dep, kind in edges.get(node, []) if kind == 'normal')
return sorted(seen)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('fixture 1', solve([], {}), [])
check('fixture 2', solve(['a'], {}), ['a'])
check('fixture 3', solve(['a'], {'a': [('b', 'normal'), ('c', 'order')]}), ['a', 'b'])
check('fixture 4', solve(['a'], {'a': [('b', 'normal')], 'b': [('c', 'normal')]}), ['a', 'b', 'c'])
check('fixture 5', solve(['z', 'a'], {}), ['a', 'z'])
check('fixture 6', solve(['a', 'a'], {'a': [('b', 'normal')]}), ['a', 'b'])
check('fixture 7', solve(['a'], {'a': [('b', 'normal')], 'b': [('a', 'normal')]}), ['a', 'b'])
check('fixture 8', solve(['a'], {'a': [('b', 'order')]}), ['a'])
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 |
|---|---|---|---|
| fixture 1 | [] | [] | Passed |
| fixture 2 | [] | ['a'] | Failed |
| fixture 3 | ['a'] | ['a', 'b'] | Failed |
| fixture 4 | ['a', 'b'] | ['a', 'b', 'c'] | Failed |
| fixture 5 | [] | ['a', 'z'] | Failed |
| fixture 6 | ['a'] | ['a', 'b'] | Failed |
| fixture 7 | ['a', 'b'] | ['a', 'b'] | Passed |
| fixture 8 | ['a'] | ['a'] | Passed |
SHA-256 / 0e514e69c34ca2e15b16f63d88a3c0de3356ea4d2f7d7010b52258f02a7e4808
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(roots, edges):
seen = set()
stack = list(roots)
while stack:
node = stack.pop()
if node in seen:
continue
seen.add(node)
if node in edges:
continue
stack.extend(dep for dep, kind in edges.get(node, []) if kind == 'normal')
return sorted(seen)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('fixture 1', solve([], {}), [])
check('fixture 2', solve(['a'], {}), ['a'])
check('fixture 3', solve(['a'], {'a': [('b', 'normal'), ('c', 'order')]}), ['a', 'b'])
check('fixture 4', solve(['a'], {'a': [('b', 'normal')], 'b': [('c', 'normal')]}), ['a', 'b', 'c'])
check('fixture 5', solve(['z', 'a'], {}), ['a', 'z'])
check('fixture 6', solve(['a', 'a'], {'a': [('b', 'normal')]}), ['a', 'b'])
check('fixture 7', solve(['a'], {'a': [('b', 'normal')], 'b': [('a', 'normal')]}), ['a', 'b'])
check('fixture 8', solve(['a'], {'a': [('b', 'order')]}), ['a'])
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 |
|---|---|---|---|
| fixture 1 | [] | [] | Passed |
| fixture 2 | ['a'] | ['a'] | Passed |
| fixture 3 | ['a'] | ['a', 'b'] | Failed |
| fixture 4 | ['a'] | ['a', 'b', 'c'] | Failed |
| fixture 5 | ['a', 'z'] | ['a', 'z'] | Passed |
| fixture 6 | ['a'] | ['a', 'b'] | Failed |
| fixture 7 | ['a'] | ['a', 'b'] | Failed |
| fixture 8 | ['a'] | ['a'] | Passed |
SHA-256 / 57624ce7b8eec97687f3fb04a1cca70a88450a66e18254e36a902ef363057dcb
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(roots, edges):
seen = set()
stack = list(roots)
while stack:
node = stack.pop()
if node in seen:
continue
seen.add(node)
stack.extend(dep for dep, kind in edges.get(node, []) if kind == 'normal')
return sorted(seen)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('fixture 1', solve([], {}), [])
check('fixture 2', solve(['a'], {}), ['a'])
check('fixture 3', solve(['a'], {'a': [('b', 'normal'), ('c', 'order')]}), ['a', 'b'])
check('fixture 4', solve(['a'], {'a': [('b', 'normal')], 'b': [('c', 'normal')]}), ['a', 'b', 'c'])
check('fixture 5', solve(['z', 'a'], {}), ['a', 'z'])
check('fixture 6', solve(['a', 'a'], {'a': [('b', 'normal')]}), ['a', 'b'])
check('fixture 7', solve(['a'], {'a': [('b', 'normal')], 'b': [('a', 'normal')]}), ['a', 'b'])
check('fixture 8', solve(['a'], {'a': [('b', 'order')]}), ['a'])
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 |
|---|---|---|---|
| fixture 1 | [] | [] | Passed |
| fixture 2 | ['a'] | ['a'] | Passed |
| fixture 3 | ['a', 'b'] | ['a', 'b'] | Passed |
| fixture 4 | ['a', 'b', 'c'] | ['a', 'b', 'c'] | Passed |
| fixture 5 | ['a', 'z'] | ['a', 'z'] | Passed |
| fixture 6 | ['a', 'b'] | ['a', 'b'] | Passed |
| fixture 7 | ['a', 'b'] | ['a', 'b'] | Passed |
| fixture 8 | ['a'] | ['a'] | Passed |
SHA-256 / fb736e0b08304b845b394f4b47290c65c7e176c81d696953ae08cfde7c6b4012
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:38:27.404636+00:00.
Case digest / 07aaa39a5a9bea680726f4f1692dc91d2818ac50ae7c6695b7e3d6cdaf7881be