Define the local evaluation task
A synthetic handout supplies text boxes, unique IDs, declared column membership and safe integer vertical positions. Read columns in the supplied column order, then each column top to bottom. Equal vertical positions use ascending ID as the local tie rule. Unknown columns or duplicate IDs are rejected rather than guessed.
- Check each box’s column association
- Order boxes inside each declared column
- Concatenate columns in declared order
Undeclared column membership goes to layout review.
Use the filled cases
| Case | Supplied input | Expected structured output | Decision and reason |
|---|---|---|---|
| Columns have staggered heights | {"columns":["left","right"],"boxes":[{"id":"R1","column":"right","y":10},{"id":"L2","column":"left","y":30},{"id":"L1","column":"left","y":5},{"id":"R2","column":"right","y":20}]} | {"order":["L1","L2","R1","R2"]} | Column grouping takes precedence over global vertical sorting. |
| Two boxes share a height | {"columns":["left"],"boxes":[{"id":"B","column":"left","y":10},{"id":"A","column":"left","y":10}]} | {"order":["A","B"]} | The explicit local ID tie rule gives A before B. |
| Fractional box position | {"columns":["left"],"boxes":[{"id":"A","column":"left","y":1.5}]} | {"error":"box-position"} | The declared integer coordinate channel rejects 1.5 rather than sorting it as a valid height. |
| Column not declared | {"columns":["left","right"],"boxes":[{"id":"X","column":"middle","y":1}]} | {"error":"box-association"} | The middle column has no declared reading position. |
Work the unknown-column case. Which output is required, and why?
Show the worked answer
{"error":"box-association"} — The middle column has no declared reading position.
Run the self-contained evaluator
import assert from 'node:assert/strict';
function evaluate(x){
if(x.boxes.some(b=>!Number.isSafeInteger(b.y)))return {error:'box-position'};
if(new Set(x.boxes.map(b=>b.id)).size!==x.boxes.length||x.boxes.some(b=>!x.columns.includes(b.column)))return {error:'box-association'};
return {order:x.columns.flatMap(column=>x.boxes.filter(b=>b.column===column).sort((a,b)=>a.y-b.y||(a.id<b.id?-1:a.id>b.id?1:0)).map(b=>b.id))};
}
const cases = [
{
"id": "staggered-columns",
"input": {
"columns": [
"left",
"right"
],
"boxes": [
{
"id": "R1",
"column": "right",
"y": 10
},
{
"id": "L2",
"column": "left",
"y": 30
},
{
"id": "L1",
"column": "left",
"y": 5
},
{
"id": "R2",
"column": "right",
"y": 20
}
]
},
"expected": {
"order": [
"L1",
"L2",
"R1",
"R2"
]
}
},
{
"id": "height-tie",
"input": {
"columns": [
"left"
],
"boxes": [
{
"id": "B",
"column": "left",
"y": 10
},
{
"id": "A",
"column": "left",
"y": 10
}
]
},
"expected": {
"order": [
"A",
"B"
]
}
},
{
"id": "fractional-position",
"input": {
"columns": [
"left"
],
"boxes": [
{
"id": "A",
"column": "left",
"y": 1.5
}
]
},
"expected": {
"error": "box-position"
}
},
{
"id": "unknown-column",
"input": {
"columns": [
"left",
"right"
],
"boxes": [
{
"id": "X",
"column": "middle",
"y": 1
}
]
},
"expected": {
"error": "box-association"
}
}
];
for (const c of cases) assert.deepEqual(evaluate(c.input), c.expected, c.id);
console.log(JSON.stringify({checked:cases.length,caseIds:cases.map(c=>c.id)}));
Use a small box map with the extracted text when diagnosing interleaved instructions. The coordinate labels are already supplied; this evaluator performs ordering and does not detect boxes from an image.