GitHub

Split Consensus

A page-axis waterfall comparing how several voters split a document into typed subdocuments against the reconciled consensus — boundary and type disagreements line up at a glance, with a per-page agreement strip and contested ranges called out.

When a split runs more than once, each voter proposes its own carve-up of the document into typed subdocuments, and Retab reconciles them into a consensus. The Split Consensus component lays those side by side as a waterfall: the consensus lane on top, each voter lane below, all aligned to the same page axis. Boundary shifts and type disagreements line up vertically, so they read at a glance.

claims-packet-2417.pdf· 12 pages · 4 voters
94% agreement
claim_form
cover_letter
id_card
invoice
remittance
consensus
invoice
remittance
id_
claim_form
gpt-4o
invoice
remittance
id_
claim_form
sonnet
invoice
remittance
id_card
claim_form
gemini
invoice
cov
remittance
id_
claim_form
mistral
invoice
remittance
id_card
claim_form
agreement

Contested ranges · 3

A heat strip under the lanes shows per-page agreement (green = every voter agrees, red = a clean split), and each contested page range is listed as a chip. Hover a chip — or any segment — to dim everything outside that range and isolate the disagreement.

Usage

Pass a single doc describing the page count, the reconciled consensus, and the voters. Everything is presentation only — wire it to whatever your run data looks like.

import { SplitConsensusView } from "@/registry/new-york-v4/blocks/split-consensus-block"
 
export function Example() {
  return (
    <div className="h-[520px] overflow-hidden rounded-xl border">
      <SplitConsensusView
        doc={{
          filename: "claims-packet-2417.pdf",
          pageCount: 8,
          consensus: [
            { type: "invoice", startPage: 0, endPage: 2 },
            { type: "remittance", startPage: 3, endPage: 5 },
            { type: "claim_form", startPage: 6, endPage: 7 },
          ],
          voters: [
            {
              label: "gpt-4o",
              segments: [
                { type: "invoice", startPage: 0, endPage: 2 },
                { type: "remittance", startPage: 3, endPage: 5 },
                { type: "claim_form", startPage: 6, endPage: 7 },
              ],
            },
            {
              label: "sonnet",
              segments: [
                { type: "invoice", startPage: 0, endPage: 2 },
                { type: "remittance", startPage: 3, endPage: 4 },
                { type: "claim_form", startPage: 5, endPage: 7 },
              ],
            },
          ],
        }}
      />
    </div>
  )
}

The SplitConsensusBlock export wraps the view with a sample document so it renders on its own with no props.

API

SplitConsensusDoc

FieldTypeDescription
pageCountnumberTotal pages in the document — sets the shared page axis.
consensusSplitSegment[]The reconciled split every voter is compared against; drawn as the top, emphasized lane.
votersSplitVoter[]The individual voter splits, one lane each.
filenamestringOptional document name shown in the header.

SplitSegment

FieldTypeDescription
typestringSubdocument type, e.g. invoice, remittance. Drives the color.
startPagenumberFirst page of the run (0-indexed, inclusive).
endPagenumberLast page of the run (0-indexed, inclusive).

SplitVoter

FieldTypeDescription
segmentsSplitSegment[]The voter's proposed split.
labelstringOptional display label, e.g. a model name. Defaults to voter N.

Components

ExportPropsDescription
SplitConsensusView{ doc: SplitConsensusDoc }The full waterfall, agreement strip and contested ranges.
SplitConsensusBlock{ doc?: SplitConsensusDoc }The view preloaded with a sample document; pass doc to override.
splitAgreementScore(doc) => numberHelper returning the mean per-page agreement (0–1).