Agent docs

Speedway: manual review queue

The manual review queue, the same shell as the jobs list, but under a filtered work surface with selection and editing pulled outside the table model.

Page and route#

/workspaces/:id/review, the index route inside the review prefix (speedway/app/routes.ts:110-111). Rendered by speedway/app/routes/workspaces/review/review.tsx.

What the reader sees#

Every attribute, part type, or content field a module could not fill on its own, across every job in the workspace, one row per open item. A toolbar filters by job, module, error kind, user, and how complete a part's critical attributes are; a row expands into an editor to fix or ignore the item in place. Selecting several rows opens a bar that approves or ignores them as one batch.

Layer 1: shell#

Same layout as the jobs list: speedway/app/routes/shell.tsx's ShellFrame renders WorkspaceNav, ShellCrumbs, and OrgActivityRail around the outlet (shell.tsx:84-106). review.tsx declares handle.nav = { active: "review", layout: "list" } (review.tsx:68-71), the same viewport-bounded fit-viewport treatment as the jobs list.

Layer 2: composition#

docs/design-language/09-page-composition.md §C names this page directly as the archetype's own namesake: "work surface | no-rail, full-width, viewport-bound; the archetype's namesake" (09-page-composition.md:52). ReviewHeader (review.tsx:399-408) sits outside the Suspense boundary the same way JobsHeader does on the jobs page, so the title never blanks while the queue streams in; the fallback is WorkspaceSkeleton again (review.tsx:413-420). Inside the resolved view, a Card wraps the toolbar, an optional bulk-selection bar, and the table or empty state as one flush surface (review.tsx:1044-1208).

Layer 3: primitives#

PrimitiveProps as calledfile:lineContract doc
PageTitleIcon={PAGE_META.review.Icon}, title="Manual review", subtitle="List of errors that Versable's modules could not resolve..."review.tsx:401-407packages/ui/docs/page-title.md
Cardwraps the toolbar, bulk bar, and table as one surfacereview.tsx:1044-1050packages/ui/docs/card.md
EmptyStatethree call sites: indexMissing (a missing Firestore index), filtered ("Nothing matches"), true-empty ("Your queue is clear")review.tsx:1078-1155packages/ui/docs/empty-state.md
DataTable<RowItem>clickSelect={false}, rowKey={(i) => \${i.jobId}:${i.id}`}, copyCells, renderRowDetail, detailIndicator={false}`review.tsx:1159-1204packages/ui/docs/table.md
SelectAllCell / SelectionCellhand-placed as the table's own __select column, outside DataTable's built-in selection modelreview.tsx:867-873packages/ui/docs/table.md
StatusPillthe Error column, kind from reasonKeyOf, plus a Tooltip-wrapped success dot for a suggested valuereview.tsx:966-993packages/ui/docs/status.md
SelectValuePicker's accepted-values picker, searchable, paired with a hidden native input for form postingreview.tsx:1789-1808packages/ui/docs/select.md
Alerttone="error", the sub-row's save failurereview.tsx:1706packages/ui/docs/alert.md

Layer 4: patterns#

  • Bulk selection action bar (/patterns/bulk-selection-bar): ReviewBulkBar (review.tsx:1490-1520), rendered when selection.selectedRows.length > 0 (review.tsx:1069-1076), carries the live selected count and one Ignore action.
  • Claimable peek panel (/patterns/peek-panel): ProductPeekPanel (review.tsx:1210-1217) opens from the Part number column's click handler, cross-job because each row carries its own jobId.
  • Attribute / spec grid (/patterns/attribute-spec-grid): ReviewSubRow's "What we found" dl (review.tsx:1424-1476), a labeled grid of module, error, candidates, and job-name rows, is speedway's own instance of this pattern's shape, though it is hand-built rather than composed from a shared kit primitive.

Layer 5: canon rules in force#

  • docs/design-language/06-tables.md §A6 (:32-33): selection scope is explicit, and the review queue is the doc's own named example of "select all in filter" living outside the model with hand-placed SelectAllCell/SelectionCell plus clickSelect={false}.
  • Same doc §C (:71): "Review queue: 2000-row server window..., fixed px widths on every column, detailIndicator off (the Fix caret owns it)," matching review.tsx:1201-1203 directly.
  • docs/design-language/04-loading-and-states.md §A7 (:33): an empty list is not one state; it requires a true/filtered/in-progress branch.
  • docs/design-language/09-page-composition.md §A1 (:14): the work-surface archetype, no activity rail, no reading-width cap.

Lapses#

The empty state splits two ways where the canon requires three. review.tsx:1078-1155 branches on indexMissing (an infrastructure error, not one of the canon's three legs) and then on filtered (canon's filtered-empty leg) versus the plain "Your queue is clear" message (canon's true-empty leg). No branch here says the queue is empty because a job is still running, the canon's in-progress-empty leg (docs/design-language/04-loading-and-states.md §A7, :33). The sibling file packages/ui/docs/empty-state.md cites speedway/app/routes/workspaces/jobs/parts.tsx:336-368 as the reference implementation of the full three-way branch, in the same app, one directory over from this page. A review queue genuinely can sit empty because a job's normalize stage hasn't finished yet, and today that reads identically to a queue that is truly clear. Fix, if revisited: add an in-progress branch keyed off whether any filtered job is still running/ingesting, following parts.tsx's shape.

Not a lapse, worth naming. NativeSelect (review.tsx:1713-1742) renders a raw <select> instead of the kit's Select, with the reason stated directly in a comment above it: "the kit Select is a button popover, and these live inside a form the browser posts." This is a considered exception, not an oversight, and the comment is the evidence for that.

See also#

@versable-git/ui · reference, canon, and method, read in place