FAILURE MAP
← Case archive

FA-37416 / Table interactions / Open access

Table column drag transaction: hidden target refusal · case 01

The table hidden target refusal result violates the stipulated table column drag transaction contract.

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

ROOT CAUSE

The hidden target refusal decision uses 'if False:' instead of 'if target not in visible:'.

VERIFIED REPAIR

Apply the complete hidden target refusal rule: if target not in visible:.

Unsuccessful approach: The attempted repair 'if target==visible[0] if visible else True:' still loses a required part of the table contract.

Case contract

Move selected columns as a schema-ordered block relative to a visible nonmoving target, preserve hidden columns, reject any locked or pane-incompatible member, and compute insertion after removing the whole source block.

Why this case matters

An offline table UI model isolates table column drag transaction, 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(order, moving, target, side, hidden, pinned, locked):
    block=[c for c in order if c in moving]
    if not block or target in block: return order
    if any(c in locked for c in block): return order
    if any(pinned.get(c,'center')!=pinned.get(target,'center') for c in block): return order
    visible=[c for c in order if c not in hidden]
    if False: return order
    remaining=[c for c in order if c not in block]
    index=(remaining.index(target) if target in remaining else 0)+(side=='after')
    return remaining[:index]+block+remaining[index:]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(1)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e1'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 2:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(2)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e2'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 3:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(3)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e3'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 4:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(4)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e4'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 5:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(5)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e5'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['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 fixtureActualExpectedOutcome
discontiguous selected columns['b', 'd', 'a', 'c', 'e1']['b', 'd', 'a', 'c', 'e1']Passed
before target['a', 'd', 'b', 'c']['a', 'd', 'b', 'c']Passed
self drop on second['a', 'b', 'c']['a', 'b', 'c']Passed
mixed locked block['a', 'b', 'c']['a', 'b', 'c']Passed
mixed pane block['a', 'b', 'c']['a', 'b', 'c']Passed
hidden target['b', 'c', 'a', 'd']['a', 'b', 'c', 'd']Failed
no drag['a']['a']Passed

SHA-256 / 8a465db0beead5b59710a6751ff85ee313ed62f67616d21c4eeff5e4c3f5d637

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(order, moving, target, side, hidden, pinned, locked):
    block=[c for c in order if c in moving]
    if not block or target in block: return order
    if any(c in locked for c in block): return order
    if any(pinned.get(c,'center')!=pinned.get(target,'center') for c in block): return order
    visible=[c for c in order if c not in hidden]
    if target==visible[0] if visible else True: return order
    remaining=[c for c in order if c not in block]
    index=(remaining.index(target) if target in remaining else 0)+(side=='after')
    return remaining[:index]+block+remaining[index:]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(1)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e1'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 2:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(2)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e2'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 3:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(3)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e3'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 4:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(4)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e4'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 5:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(5)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e5'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['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 fixtureActualExpectedOutcome
discontiguous selected columns['b', 'd', 'a', 'c', 'e1']['b', 'd', 'a', 'c', 'e1']Passed
before target['a', 'd', 'b', 'c']['a', 'd', 'b', 'c']Passed
self drop on second['a', 'b', 'c']['a', 'b', 'c']Passed
mixed locked block['a', 'b', 'c']['a', 'b', 'c']Passed
mixed pane block['a', 'b', 'c']['a', 'b', 'c']Passed
hidden target['b', 'c', 'a', 'd']['a', 'b', 'c', 'd']Failed
no drag['a']['a']Passed

SHA-256 / 88eb8e274c9cc679e3064a016f2f9844813f287c84d6ff0e26a896e68f404e03

3 / The verified repair

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

N = 1
observations = []
def solve(order, moving, target, side, hidden, pinned, locked):
    block=[c for c in order if c in moving]
    if not block or target in block: return order
    if any(c in locked for c in block): return order
    if any(pinned.get(c,'center')!=pinned.get(target,'center') for c in block): return order
    visible=[c for c in order if c not in hidden]
    if target not in visible: return order
    remaining=[c for c in order if c not in block]
    index=(remaining.index(target) if target in remaining else 0)+(side=='after')
    return remaining[:index]+block+remaining[index:]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
if N == 1:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(1)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e1'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 2:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(2)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e2'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 3:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(3)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e3'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 4:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(4)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e4'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['a'])

if N == 5:
    check('discontiguous selected columns', solve(['a','b','c','d','e'+str(5)], ['c','a'], 'd', 'after', [], {}, []), ['b', 'd', 'a', 'c', 'e5'])
    check('before target', solve(['a','b','c','d'], ['d'], 'b', 'before', [], {}, []), ['a', 'd', 'b', 'c'])
    check('self drop on second', solve(['a','b','c'], ['a','c'], 'c', 'before', [], {}, []), ['a', 'b', 'c'])
    check('mixed locked block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {}, ['b']), ['a', 'b', 'c'])
    check('mixed pane block', solve(['a','b','c'], ['a','b'], 'c', 'after', [], {'b':'left'}, []), ['a', 'b', 'c'])
    check('hidden target', solve(['a','b','c','d'], ['a'], 'c', 'after', ['b','c'], {}, []), ['a', 'b', 'c', 'd'])
    check('no drag', solve(['a'], [], 'a', 'before', [], {}, []), ['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 fixtureActualExpectedOutcome
discontiguous selected columns['b', 'd', 'a', 'c', 'e1']['b', 'd', 'a', 'c', 'e1']Passed
before target['a', 'd', 'b', 'c']['a', 'd', 'b', 'c']Passed
self drop on second['a', 'b', 'c']['a', 'b', 'c']Passed
mixed locked block['a', 'b', 'c']['a', 'b', 'c']Passed
mixed pane block['a', 'b', 'c']['a', 'b', 'c']Passed
hidden target['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']Passed
no drag['a']['a']Passed

SHA-256 / 8feb35b6bcbb885e7412939cfdd1d03bfe7b250284a4812aa5435c5446d36133

Verification & scope

Column IDs are unique and the drop target belongs to the source schema; pane labels are left, right, or center. 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:00.987108+00:00.

Case digest / 96d141cf1904a96c5b8e720685d2859807672ca118443d4f947d31d7b0b14b84