Tabular ensemble verification (P6-C.1) — Design Spec
Date: 2026-06-04 · Pin: vendor/lq-ai @ 541bd6f (bumped this branch from c22360a).
Branch: feat/tabular-ensemble-verification (off main).
Goal
Wire the now-shipped backend ensemble_verification (lq-ai #127 / Donna #6) into Donna's tabular
surface: a per-column ensemble verification toggle, the cost premium in the preview, and
verification_method surfaced on tabular cell citations — which also closes P6-B.1 (the
doc-panel "Unverified" chip on tabular citations). See [[donna-phase-status]] P6-C.1 / P6-B.1.
The pin bump + npm run gen:api is already committed on this branch (b917167): ColumnSpec gained
ensemble_verification?: boolean | null; the cost-preview response gained ensemble_cells_count? +
ensemble_premium_usd?; the results prose documents a per-cell + per-citation verification_method
(string|null: ensemble_strict / ensemble_majority; null when the column isn't ensemble-verified or
support wasn't confirmed) — loosely typed (DE-330), so hand-typed in parseTabularResults.
Part 1 — Per-column ensemble verification toggle
src/lib/tabular/types.ts: addensemble_verification?: boolean | nulltoColumnDraft.src/lib/tabular/tabularBuilder.svelte.ts: extend thesetColumnPick<>union with'ensemble_verification'; invalidColumns(), includeensemble_verification: trueon the emittedColumnSpeconly whenc.ensemble_verification === true(omit otherwise — keep the request minimal, matching howminimum_inference_tieris handled).buildRequest()needs no change (it callsvalidColumns()).src/lib/tabular/ColumnBuilder.svelte: a checkbox beside theMin. model tierselect —checked={col.ensemble_verification ?? false},onchange→builder.setColumn(col.id, { ensemble_verification: e.currentTarget.checked || null }),aria-label="Ensemble verification for {col.name || 'this column'}", label "Ensemble verification". Default off. (Skill mode is unaffected — the toggle is per ad-hoc column; ensemble for skill-defined columns is the skill's own setting.)
Part 2 — Cost premium in the preview
src/lib/tabular/CostPreviewModal.svelte: after the per-tier breakdown, whenpreview.ensemble_cells_countis truthy, render a muted line: "{ensemble_cells_count}ensemble-verified cell(s) · +${ensemble_premium_usd ?? '0'}ensemble premium (included above)".TabularPreviewCostResponsealready carries both fields (generated) — no parsing change.
Part 3 — verification_method on tabular citations
src/lib/tabular/types.ts: addverification_method?: string | nulltoTabularCitation(and, optionally,verification_method?: string | nulltoTabularCell— the backend mirrors cell→citation; the citation-level field is what the doc panel consumes, so the citation field is required, the cell field optional/nice-to-have).src/lib/tabular/parseTabularResults(intypes.ts): in the citationflatMap, parseverification_method: typeof cc.verification_method === 'string' ? cc.verification_method : null.
Part 4 — Doc-panel presentation (closes P6-B.1): "positive-or-nothing"
Decision (locked): an ensemble-verified tabular citation shows a green "✓ Verified" chip; a
non-ensemble citation (no verification_method) shows no verification chip at all (those cells
convey trust via the grid's confidence dot, not verification). Never show a misleading "Unverified" on a
cell that was never ensemble-checked.
Two coordinated changes:
- Treat the ensemble methods as verified (green). In
src/lib/citations/types.ts, addensemble_strictandensemble_majorityto the GREEN verification-method set used byciteState, so a citation whoseverification_methodis one of those resolves to'verified'. This is safe for chat: chat citations never carry those methods (they're tabular-only), so chat behavior is unchanged — confirm via the existingcitations/types.test.tscases. - Suppress the chip when verification doesn't apply. The doc panel
(
src/lib/docpanel/DocumentPanel.svelte) currently renders the verification chip unconditionally fromtab.cite. Add an explicit suppression signal so a tabular non-ensemble citation renders no chip — do NOT infer from "no verification fields", because chat unverified citations also lack a positive signal and must keep their red "Unverified" chip. Mechanism: the tabularopenCitation(src/routes/(app)/tabular/[executionId]/+page.svelte) builds theCitationcast and:- when
c.verification_methodis set → includeverified: true+verification_method(→ green "✓ Verified" via change #1); - when
c.verification_methodis null → set an explicit "verification not applicable" marker that the doc panel honors to skip the chip. The marker should be carried on the opened citation/tab in the least-invasive way (e.g. an optionalverificationApplicable?: booleanon the doc-panelCitation/open path, defaulting to applicable so all chat citations are unchanged; tabular non-ensemble sets itfalse). The plan finalizes the exact field after readingdocpanel/docPanel.svelte.ts+DocumentPanel.svelte+citations/types.ts.
- when
Testing
Unit:
tabularBuilder.svelte.test.ts:validColumns()includesensemble_verification: truewhen set, omits it when false/unset (parallel to the existingminimum_inference_tiertest).ColumnBuilder.svelte.test.ts: toggling the checkbox callssetColumnwithensemble_verification.CostPreviewModal.svelte.test.ts: premium line renders whenensemble_cells_count> 0; absent when 0/missing.types.test.ts(parseTabularResults):verification_methodparsed from a raw citation; null when absent.citations/types.test.ts:ensemble_strict/ensemble_majority→citeState'verified'.- Doc-panel chip: a unit test (extend
DocumentPanel.svelte.test.ts) that the chip is suppressed when the marker says verification doesn't apply, and shows green "✓ Verified" for an ensemble citation.
Live e2e: requires rebuilding the backend from the new pin — docker compose up -d --build api gateway arq-worker ingest-worker donna-web (541bd6f). Then extend tests/tabular-review.spec.ts (or a
focused case): build a review with one ensemble-verified column, confirm the preview shows the
ensemble premium, run it (a real ensemble judge run — slower/costs judge calls), and assert a cell's
citation opens the doc panel with the green "✓ Verified" chip. Keep the assertion resilient (the LLM
content varies); gate on the chip + premium, not exact text. Use a PDF fixture (.txt won't ingest).
Success criteria
- A per-column Ensemble verification checkbox in the builder; checked columns send
ensemble_verification: true; the preview shows the ensemble cell count + premium. - Tabular cell citations carry
verification_method; ensemble-verified citations show a green "✓ Verified" chip in the doc panel; non-ensemble citations show no verification chip (P6-B.1 closed — no more misleading "Unverified"). - Chat citation verification behavior is unchanged.
npm run check= 0/0; no new lint;npx vitest rungreen; live e2e passes against the 541bd6f backend.
Out of scope
- Surfacing
verification_methodinside the grid/CellDetailtext (the doc-panel chip is the trust signal; the grid keeps its confidence dot). OptionalTabularCell.verification_methodmay be parsed but need not be displayed in the grid. - Provider-keys / BYOK (separate, still upstream-pending).