FAILURE MAP
← Case archive

FA-37191 / Table interactions / Open access

Atomic table row editing: editable schema · case 01

The table editable schema result violates the stipulated atomic table row editing contract.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The editable schema decision uses 'if True' instead of "if c.get('editable',True)".

VERIFIED REPAIR

Apply the complete editable schema rule: if c.get('editable',True).

Unsuccessful approach: The attempted repair "if c.get('editable',False)" still loses a required part of the table contract.

Case contract

Row commits validate the merged draft atomically, reject unknown schema fields, ignore readonly fields, preserve untouched cells and stable identity, reject revision conflicts, suppress no-ops, and increment the revision only after actual changes.

Why this case matters

An offline table UI model isolates atomic table row editing, including adversarial row/column relationships.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(row, draft, schema, revision, base_revision):
    allowed={c['id'] for c in schema if True}
    unknown=sorted(set(draft)-{c['id'] for c in schema})
    changes={k:v for k,v in draft.items() if k in allowed and row.get(k)!=v}
    errors={c['id']:'required' for c in schema if c.get('required') and draft.get(c['id'],row.get(c['id'])) in ('',None)}
    if unknown: return {'status':'unknown','fields':unknown,'row':row}
    if errors: return {'status':'invalid','fields':errors,'row':row}
    if base_revision!=revision: return {'status':'conflict','fields':[],'row':row}
    if not changes: return {'status':'unchanged','fields':[],'row':row}
    updated=dict(row); updated.update(changes)
    return {'status':'saved','fields':sorted(changes),'row':updated,'revision':revision+1}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':1+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 4, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 2:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':2+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 5, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 3:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':3+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 6, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 4:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':4+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 7, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 5:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':5+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 8, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

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 fixtureActualExpectedOutcome
partial draft{'fields': ['a'], 'revision': 5, 'row': {'a': 4, 'b': 2, 'id': 'r'}, 'status': 'saved'}{'fields': ['a'], 'revision': 5, 'row': {'a': 4, 'b': 2, 'id': 'r'}, 'status': 'saved'}Passed
readonly draft{'fields': ['b'], 'revision': 5, 'row': {'a': 1, 'b': 9, 'id': 'r'}, 'status': 'saved'}{'fields': [], 'row': {'a': 1, 'b': 2, 'id': 'r'}, 'status': 'unchanged'}Failed
unknown draft{'fields': ['missing'], 'row': {'a': 1, 'id': 'r'}, 'status': 'unknown'}{'fields': ['missing'], 'row': {'a': 1, 'id': 'r'}, 'status': 'unknown'}Passed
required clear{'fields': {'a': 'required'}, 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'invalid'}{'fields': {'a': 'required'}, 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'invalid'}Passed
required untouched{'fields': ['b'], 'revision': 5, 'row': {'a': 'ok', 'b': 0, 'id': 'r'}, 'status': 'saved'}{'fields': ['b'], 'revision': 5, 'row': {'a': 'ok', 'b': 0, 'id': 'r'}, 'status': 'saved'}Passed
stale row{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'conflict'}{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'conflict'}Passed
same value{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'unchanged'}{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'unchanged'}Passed

SHA-256 / cbe8f0bf81417f6b1b5c05c2692244093ae6ad45acbcf3123dc32438d4baab55

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(row, draft, schema, revision, base_revision):
    allowed={c['id'] for c in schema if c.get('editable',False)}
    unknown=sorted(set(draft)-{c['id'] for c in schema})
    changes={k:v for k,v in draft.items() if k in allowed and row.get(k)!=v}
    errors={c['id']:'required' for c in schema if c.get('required') and draft.get(c['id'],row.get(c['id'])) in ('',None)}
    if unknown: return {'status':'unknown','fields':unknown,'row':row}
    if errors: return {'status':'invalid','fields':errors,'row':row}
    if base_revision!=revision: return {'status':'conflict','fields':[],'row':row}
    if not changes: return {'status':'unchanged','fields':[],'row':row}
    updated=dict(row); updated.update(changes)
    return {'status':'saved','fields':sorted(changes),'row':updated,'revision':revision+1}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':1+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 4, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 2:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':2+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 5, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 3:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':3+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 6, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 4:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':4+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 7, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 5:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':5+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 8, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

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 fixtureActualExpectedOutcome
partial draft{'fields': [], 'row': {'a': 1, 'b': 2, 'id': 'r'}, 'status': 'unchanged'}{'fields': ['a'], 'revision': 5, 'row': {'a': 4, 'b': 2, 'id': 'r'}, 'status': 'saved'}Failed
readonly draft{'fields': [], 'row': {'a': 1, 'b': 2, 'id': 'r'}, 'status': 'unchanged'}{'fields': [], 'row': {'a': 1, 'b': 2, 'id': 'r'}, 'status': 'unchanged'}Passed
unknown draft{'fields': ['missing'], 'row': {'a': 1, 'id': 'r'}, 'status': 'unknown'}{'fields': ['missing'], 'row': {'a': 1, 'id': 'r'}, 'status': 'unknown'}Passed
required clear{'fields': {'a': 'required'}, 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'invalid'}{'fields': {'a': 'required'}, 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'invalid'}Passed
required untouched{'fields': [], 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'unchanged'}{'fields': ['b'], 'revision': 5, 'row': {'a': 'ok', 'b': 0, 'id': 'r'}, 'status': 'saved'}Failed
stale row{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'conflict'}{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'conflict'}Passed
same value{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'unchanged'}{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'unchanged'}Passed

SHA-256 / 69de6164a0d52aef3fd822e4de3b4791f542f558a64273ca4f3239a08494c5c7

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(row, draft, schema, revision, base_revision):
    allowed={c['id'] for c in schema if c.get('editable',True)}
    unknown=sorted(set(draft)-{c['id'] for c in schema})
    changes={k:v for k,v in draft.items() if k in allowed and row.get(k)!=v}
    errors={c['id']:'required' for c in schema if c.get('required') and draft.get(c['id'],row.get(c['id'])) in ('',None)}
    if unknown: return {'status':'unknown','fields':unknown,'row':row}
    if errors: return {'status':'invalid','fields':errors,'row':row}
    if base_revision!=revision: return {'status':'conflict','fields':[],'row':row}
    if not changes: return {'status':'unchanged','fields':[],'row':row}
    updated=dict(row); updated.update(changes)
    return {'status':'saved','fields':sorted(changes),'row':updated,'revision':revision+1}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':1+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 4, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 2:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':2+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 5, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 3:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':3+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 6, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 4:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':4+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 7, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

if N == 5:
    check('partial draft', solve({'id':'r','a':1,'b':2}, {'a':5+3}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'saved', 'fields': ['a'], 'row': {'id': 'r', 'a': 8, 'b': 2}, 'revision': 5})
    check('readonly draft', solve({'id':'r','a':1,'b':2}, {'b':9}, [{'id':'a'},{'id':'b','editable':False}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1, 'b': 2}})
    check('unknown draft', solve({'id':'r','a':1}, {'missing':2}, [{'id':'a'}], 4, 4), {'status': 'unknown', 'fields': ['missing'], 'row': {'id': 'r', 'a': 1}})
    check('required clear', solve({'id':'r','a':'ok','b':2}, {'a':''}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'invalid', 'fields': {'a': 'required'}, 'row': {'id': 'r', 'a': 'ok', 'b': 2}})
    check('required untouched', solve({'id':'r','a':'ok','b':2}, {'b':0}, [{'id':'a','required':True},{'id':'b'}], 4, 4), {'status': 'saved', 'fields': ['b'], 'row': {'id': 'r', 'a': 'ok', 'b': 0}, 'revision': 5})
    check('stale row', solve({'id':'r','a':1}, {'a':2}, [{'id':'a'}], 4, 3), {'status': 'conflict', 'fields': [], 'row': {'id': 'r', 'a': 1}})
    check('same value', solve({'id':'r','a':1}, {'a':1}, [{'id':'a'}], 4, 4), {'status': 'unchanged', 'fields': [], 'row': {'id': 'r', 'a': 1}})

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 fixtureActualExpectedOutcome
partial draft{'fields': ['a'], 'revision': 5, 'row': {'a': 4, 'b': 2, 'id': 'r'}, 'status': 'saved'}{'fields': ['a'], 'revision': 5, 'row': {'a': 4, 'b': 2, 'id': 'r'}, 'status': 'saved'}Passed
readonly draft{'fields': [], 'row': {'a': 1, 'b': 2, 'id': 'r'}, 'status': 'unchanged'}{'fields': [], 'row': {'a': 1, 'b': 2, 'id': 'r'}, 'status': 'unchanged'}Passed
unknown draft{'fields': ['missing'], 'row': {'a': 1, 'id': 'r'}, 'status': 'unknown'}{'fields': ['missing'], 'row': {'a': 1, 'id': 'r'}, 'status': 'unknown'}Passed
required clear{'fields': {'a': 'required'}, 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'invalid'}{'fields': {'a': 'required'}, 'row': {'a': 'ok', 'b': 2, 'id': 'r'}, 'status': 'invalid'}Passed
required untouched{'fields': ['b'], 'revision': 5, 'row': {'a': 'ok', 'b': 0, 'id': 'r'}, 'status': 'saved'}{'fields': ['b'], 'revision': 5, 'row': {'a': 'ok', 'b': 0, 'id': 'r'}, 'status': 'saved'}Passed
stale row{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'conflict'}{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'conflict'}Passed
same value{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'unchanged'}{'fields': [], 'row': {'a': 1, 'id': 'r'}, 'status': 'unchanged'}Passed

SHA-256 / 78c3b45fabae211ccd7d70b8d1d0f12fb803c906e5517e6cc603863397e25c7a

Verification & scope

Schema IDs are unique, revisions are integers, and required validation means only None or empty string. Deterministic offline table UI model; no browser, DOM, framework, or standards conformance is claimed. 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:42:58.797322+00:00.

Case digest / 6281a6d53475d3e9b9b4c59ea8feec3f997b05bff890fcdd720401b5ae506bb6