FA-221 / Serialization / Open access
Sorting only the root leaves unstable nested JSON output · case 01
Equivalent nested objects produce different byte strings depending on insertion order.
ROOT CAUSE
Only the outer object's keys are ordered before serialization.
VERIFIED REPAIR
Apply recursive object-key ordering in the serializer with explicit whitespace, Unicode, and finite-number settings.
Unsuccessful approach: Rebuilding a sorted top-level dictionary leaves objects nested in values and arrays in insertion order.
Case contract
Serialize a JSON-compatible object with string keys using Python's JSON representation, recursive key sorting, no optional spaces, literal Unicode, and finite numbers only. Return None for unsupported values. This is a specified deterministic format, not a claim of RFC 8785 conformance.
Why this case matters
Bytewise snapshots and content digests require deterministic nested serialization. Sorting only the visible outer map leaves hidden order dependence.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(value):
try:
return json.dumps(value, ensure_ascii=False, separators=(',', ':'), allow_nan=False)
except (TypeError, ValueError):
return None
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('root ordering', solve({'z': N, 'a': 0}), '{"a":0,"z":' + str(N) + '}')
check('nested ordering', solve({'outer': {'z': N, 'a': 0}}), '{"outer":{"a":0,"z":' + str(N) + '}}')
check('objects inside arrays', solve({'items': [{'z': i, 'a': 0} for i in range(N)]}), '{"items":[' + ','.join('{"a":0,"z":' + str(i) + '}' for i in range(N)) + ']}')
check('literal Unicode preserved', solve({'é': '界' * N, 'a': 0}), '{"a":0,"é":"' + '界' * N + '"}')
check('no optional whitespace', solve({'x': [1, True, None]}), '{"x":[1,true,null]}')
check('empty object', solve({}), '{}')
check('nonfinite number rejected', solve({'x': float('nan')}), None)
check('unsupported bytes rejected', solve({'x': b'abc'}), None)
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 |
|---|---|---|---|
| root ordering | {"z":1,"a":0} | {"a":0,"z":1} | Failed |
| nested ordering | {"outer":{"z":1,"a":0}} | {"outer":{"a":0,"z":1}} | Failed |
| objects inside arrays | {"items":[{"z":0,"a":0}]} | {"items":[{"a":0,"z":0}]} | Failed |
| literal Unicode preserved | {"é":"界","a":0} | {"a":0,"é":"界"} | Failed |
| no optional whitespace | {"x":[1,true,null]} | {"x":[1,true,null]} | Passed |
| empty object | {} | {} | Passed |
| nonfinite number rejected | None | None | Passed |
| unsupported bytes rejected | None | None | Passed |
SHA-256 / 99f6bc4feb5bc7ed0aa3c5d575a743dbf0165bc5f3b1d2405e18136c6f9bf31c
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(value):
try:
value = dict(sorted(value.items()))
return json.dumps(value, ensure_ascii=False, separators=(',', ':'), allow_nan=False)
except (TypeError, ValueError):
return None
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('root ordering', solve({'z': N, 'a': 0}), '{"a":0,"z":' + str(N) + '}')
check('nested ordering', solve({'outer': {'z': N, 'a': 0}}), '{"outer":{"a":0,"z":' + str(N) + '}}')
check('objects inside arrays', solve({'items': [{'z': i, 'a': 0} for i in range(N)]}), '{"items":[' + ','.join('{"a":0,"z":' + str(i) + '}' for i in range(N)) + ']}')
check('literal Unicode preserved', solve({'é': '界' * N, 'a': 0}), '{"a":0,"é":"' + '界' * N + '"}')
check('no optional whitespace', solve({'x': [1, True, None]}), '{"x":[1,true,null]}')
check('empty object', solve({}), '{}')
check('nonfinite number rejected', solve({'x': float('nan')}), None)
check('unsupported bytes rejected', solve({'x': b'abc'}), None)
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 |
|---|---|---|---|
| root ordering | {"a":0,"z":1} | {"a":0,"z":1} | Passed |
| nested ordering | {"outer":{"z":1,"a":0}} | {"outer":{"a":0,"z":1}} | Failed |
| objects inside arrays | {"items":[{"z":0,"a":0}]} | {"items":[{"a":0,"z":0}]} | Failed |
| literal Unicode preserved | {"a":0,"é":"界"} | {"a":0,"é":"界"} | Passed |
| no optional whitespace | {"x":[1,true,null]} | {"x":[1,true,null]} | Passed |
| empty object | {} | {} | Passed |
| nonfinite number rejected | None | None | Passed |
| unsupported bytes rejected | None | None | Passed |
SHA-256 / f937caa1decc34e4c07af6f30d0258da0e65043ee5d26d9f40fee60b38e169bf
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(value):
try:
return json.dumps(value, sort_keys=True, ensure_ascii=False, separators=(',', ':'), allow_nan=False)
except (TypeError, ValueError):
return None
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('root ordering', solve({'z': N, 'a': 0}), '{"a":0,"z":' + str(N) + '}')
check('nested ordering', solve({'outer': {'z': N, 'a': 0}}), '{"outer":{"a":0,"z":' + str(N) + '}}')
check('objects inside arrays', solve({'items': [{'z': i, 'a': 0} for i in range(N)]}), '{"items":[' + ','.join('{"a":0,"z":' + str(i) + '}' for i in range(N)) + ']}')
check('literal Unicode preserved', solve({'é': '界' * N, 'a': 0}), '{"a":0,"é":"' + '界' * N + '"}')
check('no optional whitespace', solve({'x': [1, True, None]}), '{"x":[1,true,null]}')
check('empty object', solve({}), '{}')
check('nonfinite number rejected', solve({'x': float('nan')}), None)
check('unsupported bytes rejected', solve({'x': b'abc'}), None)
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 |
|---|---|---|---|
| root ordering | {"a":0,"z":1} | {"a":0,"z":1} | Passed |
| nested ordering | {"outer":{"a":0,"z":1}} | {"outer":{"a":0,"z":1}} | Passed |
| objects inside arrays | {"items":[{"a":0,"z":0}]} | {"items":[{"a":0,"z":0}]} | Passed |
| literal Unicode preserved | {"a":0,"é":"界"} | {"a":0,"é":"界"} | Passed |
| no optional whitespace | {"x":[1,true,null]} | {"x":[1,true,null]} | Passed |
| empty object | {} | {} | Passed |
| nonfinite number rejected | None | None | Passed |
| unsupported bytes rejected | None | None | Passed |
SHA-256 / f85888cfa7d4256ccea981f83ffc53ad1169e26ee3b5427215d8c55de7b9f433
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:51.498064+00:00.
Case digest / 5391319240792b01c3364ad36a81639d4dd5beb6033cc4c9be96c11bb77649af