FAILURE MAP
← Case archive

FA-38296 / Table interactions / Open access

Table column schema migration: alias target validation · case 01

The table alias target validation result violates the stipulated table column schema migration contract.

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

ROOT CAUSE

The alias target validation decision uses 'None' instead of 'aliases.get(k) if aliases.get(k) in ids else None'.

VERIFIED REPAIR

Apply the complete alias target validation rule: aliases.get(k) if aliases.get(k) in ids else None.

Unsuccessful approach: The attempted repair 'k if k in ids else None' still loses a required part of the table contract.

Case contract

Schema migration gives surviving IDs precedence over aliases, validates alias targets, deduplicates migrated order/selection and appends new columns. Direct widths override alias widths, required columns stay visible, drafts migrate only across equal types, and deleted anchors clear.

Why this case matters

An offline table UI model isolates table column schema migration, 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(old, new, aliases, view, drafts, selected, anchor):
    ids=[c['id'] for c in new]
    def remap(k):
        if k in ids: return k
        return None
    order=[]
    for k in view['order']:
        mapped=remap(k)
        if mapped is not None and mapped not in order: order.append(mapped)
    order += [k for k in ids if k not in order]
    widths={}
    for k,v in view['widths'].items():
        mapped=remap(k)
        if mapped is not None and (mapped not in widths or k==mapped): widths[mapped]=v
    hidden=[k for k in order if any(remap(x)==k for x in view['hidden']) and not next(c for c in new if c['id']==k).get('required')]
    newdraft=[]
    oldtypes={c['id']:c['type'] for c in old}; newtypes={c['id']:c['type'] for c in new}
    for r,c,value in drafts:
        mapped=remap(c)
        if mapped is not None and oldtypes.get(c)==newtypes[mapped]: newdraft.append((r,mapped,value))
    newsel=[]
    for r,c in selected:
        mapped=remap(c)
        if mapped is not None and (r,mapped) not in newsel: newsel.append((r,mapped))
    return {'order':order,'widths':widths,'hidden':hidden,'drafts':newdraft,'selected':newsel,'anchor':(anchor[0],remap(anchor[1])) if anchor is not None and remap(anchor[1]) is not None else None}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':1+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 8}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 2:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':2+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 9}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 3:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':3+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 10}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 4:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':4+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 11}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 5:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':5+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 12}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': 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 fixtureActualExpectedOutcome
renamed numeric column{'anchor': None, 'drafts': [['r', 'b', 'x']], 'hidden': [], 'order': ['b', 'new', 'fresh'], 'selected': [['r', 'b']], 'widths': {}}{'anchor': ['r', 'new'], 'drafts': [['r', 'new', 3], ['r', 'b', 'x']], 'hidden': ['new'], 'order': ['new', 'b', 'fresh'], 'selected': [['r', 'new'], ['r', 'b']], 'widths': {'new': 8}}Failed
direct id wins alias{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a', 'b'], 'selected': [], 'widths': {'a': 4, 'b': 5}}{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a', 'b'], 'selected': [], 'widths': {'a': 4, 'b': 5}}Passed
merged aliases direct widths last{'anchor': None, 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [], 'widths': {'a': 8}}{'anchor': None, 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {'a': 8}}Failed
type-changed draft{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {}}{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {}}Passed
removed schema key{'anchor': None, 'drafts': [], 'hidden': [], 'order': [], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': [], 'order': [], 'selected': [], 'widths': {}}Passed
reverse saved order{'anchor': None, 'drafts': [], 'hidden': ['b'], 'order': ['c', 'b', 'a'], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': ['b'], 'order': ['c', 'b', 'a'], 'selected': [], 'widths': {}}Passed
required renamed column{'anchor': None, 'drafts': [], 'hidden': ['a'], 'order': ['a', 'new'], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': ['a'], 'order': ['a', 'new'], 'selected': [], 'widths': {}}Passed

SHA-256 / 90ba48243bb3a073e720b03c315786e83dc18597ba7296a3f839a9f2202e09a2

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(old, new, aliases, view, drafts, selected, anchor):
    ids=[c['id'] for c in new]
    def remap(k):
        if k in ids: return k
        return k if k in ids else None
    order=[]
    for k in view['order']:
        mapped=remap(k)
        if mapped is not None and mapped not in order: order.append(mapped)
    order += [k for k in ids if k not in order]
    widths={}
    for k,v in view['widths'].items():
        mapped=remap(k)
        if mapped is not None and (mapped not in widths or k==mapped): widths[mapped]=v
    hidden=[k for k in order if any(remap(x)==k for x in view['hidden']) and not next(c for c in new if c['id']==k).get('required')]
    newdraft=[]
    oldtypes={c['id']:c['type'] for c in old}; newtypes={c['id']:c['type'] for c in new}
    for r,c,value in drafts:
        mapped=remap(c)
        if mapped is not None and oldtypes.get(c)==newtypes[mapped]: newdraft.append((r,mapped,value))
    newsel=[]
    for r,c in selected:
        mapped=remap(c)
        if mapped is not None and (r,mapped) not in newsel: newsel.append((r,mapped))
    return {'order':order,'widths':widths,'hidden':hidden,'drafts':newdraft,'selected':newsel,'anchor':(anchor[0],remap(anchor[1])) if anchor is not None and remap(anchor[1]) is not None else None}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':1+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 8}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 2:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':2+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 9}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 3:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':3+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 10}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 4:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':4+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 11}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 5:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':5+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 12}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': 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 fixtureActualExpectedOutcome
renamed numeric column{'anchor': None, 'drafts': [['r', 'b', 'x']], 'hidden': [], 'order': ['b', 'new', 'fresh'], 'selected': [['r', 'b']], 'widths': {}}{'anchor': ['r', 'new'], 'drafts': [['r', 'new', 3], ['r', 'b', 'x']], 'hidden': ['new'], 'order': ['new', 'b', 'fresh'], 'selected': [['r', 'new'], ['r', 'b']], 'widths': {'new': 8}}Failed
direct id wins alias{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a', 'b'], 'selected': [], 'widths': {'a': 4, 'b': 5}}{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a', 'b'], 'selected': [], 'widths': {'a': 4, 'b': 5}}Passed
merged aliases direct widths last{'anchor': None, 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [], 'widths': {'a': 8}}{'anchor': None, 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {'a': 8}}Failed
type-changed draft{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {}}{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {}}Passed
removed schema key{'anchor': None, 'drafts': [], 'hidden': [], 'order': [], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': [], 'order': [], 'selected': [], 'widths': {}}Passed
reverse saved order{'anchor': None, 'drafts': [], 'hidden': ['b'], 'order': ['c', 'b', 'a'], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': ['b'], 'order': ['c', 'b', 'a'], 'selected': [], 'widths': {}}Passed
required renamed column{'anchor': None, 'drafts': [], 'hidden': ['a'], 'order': ['a', 'new'], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': ['a'], 'order': ['a', 'new'], 'selected': [], 'widths': {}}Passed

SHA-256 / 2cc1a896c8486a68a07c94e20b8b40411343df49cae95d90c15fd1a6a9ce68f0

3 / The verified repair

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

N = 1
observations = []
def solve(old, new, aliases, view, drafts, selected, anchor):
    ids=[c['id'] for c in new]
    def remap(k):
        if k in ids: return k
        return aliases.get(k) if aliases.get(k) in ids else None
    order=[]
    for k in view['order']:
        mapped=remap(k)
        if mapped is not None and mapped not in order: order.append(mapped)
    order += [k for k in ids if k not in order]
    widths={}
    for k,v in view['widths'].items():
        mapped=remap(k)
        if mapped is not None and (mapped not in widths or k==mapped): widths[mapped]=v
    hidden=[k for k in order if any(remap(x)==k for x in view['hidden']) and not next(c for c in new if c['id']==k).get('required')]
    newdraft=[]
    oldtypes={c['id']:c['type'] for c in old}; newtypes={c['id']:c['type'] for c in new}
    for r,c,value in drafts:
        mapped=remap(c)
        if mapped is not None and oldtypes.get(c)==newtypes[mapped]: newdraft.append((r,mapped,value))
    newsel=[]
    for r,c in selected:
        mapped=remap(c)
        if mapped is not None and (r,mapped) not in newsel: newsel.append((r,mapped))
    return {'order':order,'widths':widths,'hidden':hidden,'drafts':newdraft,'selected':newsel,'anchor':(anchor[0],remap(anchor[1])) if anchor is not None and remap(anchor[1]) is not None else None}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':1+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 8}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 2:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':2+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 9}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 3:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':3+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 10}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 4:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':4+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 11}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': None})

if N == 5:
    check('renamed numeric column', solve([{'id':'old','type':'number'},{'id':'b','type':'text'}], [{'id':'new','type':'number'},{'id':'b','type':'text'},{'id':'fresh','type':'text'}], {'old':'new'}, {'order':['old','b'],'widths':{'old':5+7},'hidden':['old']}, [('r','old',3),('r','b','x')], [('r','old'),('r','b')], ('r','old')), {'order': ['new', 'b', 'fresh'], 'widths': {'new': 12}, 'hidden': ['new'], 'drafts': [('r', 'new', 3), ('r', 'b', 'x')], 'selected': [('r', 'new'), ('r', 'b')], 'anchor': ('r', 'new')})
    check('direct id wins alias', solve([{'id':'a','type':'text'},{'id':'b','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'}], {'a':'b'}, {'order':['a','b'],'widths':{'a':4,'b':5},'hidden':[]}, [], [], ('r','a')), {'order': ['a', 'b'], 'widths': {'a': 4, 'b': 5}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': ('r', 'a')})
    check('merged aliases direct widths last', solve([{'id':'x','type':'text'},{'id':'y','type':'text'},{'id':'a','type':'text'}], [{'id':'a','type':'text'}], {'x':'a','y':'a'}, {'order':['x','y','a'],'widths':{'x':4,'a':8,'y':6},'hidden':[]}, [], [('r','x'),('r','y')], None), {'order': ['a'], 'widths': {'a': 8}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': None})
    check('type-changed draft', solve([{'id':'a','type':'text'}], [{'id':'a','type':'number'}], {}, {'order':['a'],'widths':{},'hidden':[]}, [('r','a','1')], [('r','a')], ('r','a')), {'order': ['a'], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [('r', 'a')], 'anchor': ('r', 'a')})
    check('removed schema key', solve([{'id':'gone','type':'text'}], [], {'gone':'also-gone'}, {'order':['gone'],'widths':{'gone':9},'hidden':['gone']}, [('r','gone','v')], [('r','gone')], ('r','gone')), {'order': [], 'widths': {}, 'hidden': [], 'drafts': [], 'selected': [], 'anchor': None})
    check('reverse saved order', solve([{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], [{'id':'a','type':'text'},{'id':'b','type':'text'},{'id':'c','type':'text'}], {}, {'order':['c','b','a'],'widths':{},'hidden':['b']}, [], [], None), {'order': ['c', 'b', 'a'], 'widths': {}, 'hidden': ['b'], 'drafts': [], 'selected': [], 'anchor': None})
    check('required renamed column', solve([{'id':'old','type':'text'}], [{'id':'a','type':'text'},{'id':'new','type':'text','required':True}], {'old':'new'}, {'order':['a','old'],'widths':{},'hidden':['old','a']}, [], [], None), {'order': ['a', 'new'], 'widths': {}, 'hidden': ['a'], 'drafts': [], 'selected': [], 'anchor': 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 fixtureActualExpectedOutcome
renamed numeric column{'anchor': ['r', 'new'], 'drafts': [['r', 'new', 3], ['r', 'b', 'x']], 'hidden': ['new'], 'order': ['new', 'b', 'fresh'], 'selected': [['r', 'new'], ['r', 'b']], 'widths': {'new': 8}}{'anchor': ['r', 'new'], 'drafts': [['r', 'new', 3], ['r', 'b', 'x']], 'hidden': ['new'], 'order': ['new', 'b', 'fresh'], 'selected': [['r', 'new'], ['r', 'b']], 'widths': {'new': 8}}Passed
direct id wins alias{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a', 'b'], 'selected': [], 'widths': {'a': 4, 'b': 5}}{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a', 'b'], 'selected': [], 'widths': {'a': 4, 'b': 5}}Passed
merged aliases direct widths last{'anchor': None, 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {'a': 8}}{'anchor': None, 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {'a': 8}}Passed
type-changed draft{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {}}{'anchor': ['r', 'a'], 'drafts': [], 'hidden': [], 'order': ['a'], 'selected': [['r', 'a']], 'widths': {}}Passed
removed schema key{'anchor': None, 'drafts': [], 'hidden': [], 'order': [], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': [], 'order': [], 'selected': [], 'widths': {}}Passed
reverse saved order{'anchor': None, 'drafts': [], 'hidden': ['b'], 'order': ['c', 'b', 'a'], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': ['b'], 'order': ['c', 'b', 'a'], 'selected': [], 'widths': {}}Passed
required renamed column{'anchor': None, 'drafts': [], 'hidden': ['a'], 'order': ['a', 'new'], 'selected': [], 'widths': {}}{'anchor': None, 'drafts': [], 'hidden': ['a'], 'order': ['a', 'new'], 'selected': [], 'widths': {}}Passed

SHA-256 / 5ce8751763296f2cd68024dfc112be5dca466c1e0cc5f6eba7eb0400ba8ba7e5

Verification & scope

Old/new schema IDs are unique and aliases are single-hop; draft compatibility requires exact stipulated type-name equality. 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:43:09.705265+00:00.

Case digest / ff976669e84574c8a1cabdfc7049528ab1d091191c82f28e4dde55ce43866ee5