Engineering Journal
Pdf Processor
Pdf Processor

Four Bugs in One Algorithm Design

2026-07-17

TLDR

During the design review of our v1 bipartite column detection algorithm, four compounding mathematical edge-case bugs were identified prior to shipping to production: reversed gutter tolerance directions, viewport-frame instead of content-frame persistence checks, global band count denominator pollution, and two-pointer interval scan failures. Correcting these four geometric constraints produced a bulletproof multi-column layout engine.
Geometric DefectFaulty Math FormulationStructural ConsequenceCorrected Formulation
Reversed TolerancemaxX <= X + tolOverlapping bands counted as clean splitmaxX <= X - tol (Shrinks inward)
Viewport Persistenceb.y <= vpHeight 0.20Rejects short 2-column articlesb.y <= contentTop + contentSpan 0.20
Global Denominator/ narrowBands.lengthRejects 2-column sections on hybrid pages/ localCoexistenceBands.length
Two-Pointer WalkUn-merged maxX/minX listsMisses overlapping band spansInterval merging prior to gap search

Technical defect analysis & fixes

Defect 1: reversed gutter tolerance direction

// REFACTORED: Inward Tolerance Partitioning
const leftOnly  = narrowBands.filter(b => b.maxX <= X - tol);
const rightOnly = narrowBands.filter(b => b.minX >= X + tol);

Defect 2: viewport-relative persistence scaling

Faulty Logic: Evaluating header confinement against viewportHeight 0.20 rejected valid 2-column layouts on pages where text occupied only the top half of the page.
// REFACTORED: Content-Relative Persistence
const contentTop = Math.min(...narrowBands.map(b => b.y));
const contentBottom = Math.max(...narrowBands.map(b => b.y));
const contentSpan = contentBottom - contentTop || 1;

const persistenceThreshold = contentTop + contentSpan * 0.20;

Defect 3: global denominator pollution on hybrid layouts

// REFACTORED: Coexistence Zone Denominator
const coexistTop = Math.max(Math.min(...leftOnly.map(b => b.y)), Math.min(...rightOnly.map(b => b.y)));
const coexistBottom = Math.min(Math.max(...leftOnly.map(b => b.y)), Math.max(...rightOnly.map(b => b.y)));

if (coexistBottom < coexistTop) return false; // Populations are vertically disjoint

const localCoexistenceBands = narrowBands.filter(b => b.y >= coexistTop && b.y <= coexistBottom); const commitmentRatio = (leftOnly.length + rightOnly.length) / localCoexistenceBands.length;

if (commitmentRatio < 0.40) return false;

Defect 4: two-pointer interval overlap failures

// REFACTORED: Interval Merging Before Candidate Search
const sortedBands = [...narrowBands].sort((a, b) => a.minX - b.minX);
const mergedSpans = [];

for (const band of sortedBands) { if (mergedSpans.length && band.minX <= mergedSpans.at(-1).hi) { mergedSpans.at(-1).hi = Math.max(mergedSpans.at(-1).hi, band.maxX); } else { mergedSpans.push({ lo: band.minX, hi: band.maxX }); } }

Rule of thumb: Evaluate persistence relative to actual content bounds rather than page frames, and calculate layout ratios within local coexistence intersections.
Read this post in the full Engineering Journal →