Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-2500Done

design/backlog still annotates every row `role="row"` + `aria-selected` — the asset describes the composition MOTIR-2493 removed

Surfaced by MOTIR-2493 while fixing the shipped role composition — filed rather than absorbed, because a design/**-only diff takes the design/MOTIR-<id>-<slug> branch prefix (CI skips E2E + the Vercel preview) and cannot ride the same PR as MOTIR-2493's runtime-code diff. One PR, motir-core.

The measurement

MOTIR-2493 chose list + listitem for the backlog's ranked rows: BacklogRows' scroll viewport stays role="list", and BacklogRowBody now renders role="listitem" with aria-posinset/aria-setsize, and NO aria-selected (not an allowed attribute on listitem; the sibling checkbox's aria-checked carries selection).

The design asset still specifies the composition that was removed.

⚠️ AMENDED AT RUN TIME (2026-08-09, rung 2) — the measurement below undercounted the defect by two thirds. The card measured ONE file. design/backlog/ holds THREE mocks that all draw the same /backlog rows, and all three carried the stale annotation:

file<div role="row"> elements
backlog.mock.html21 (+1 prose mention = the 22 grep hits below)
backlog-filter.mock.html9
backlog-scale.mock.html8

38 row elements, and not one of them had a legal parent: grep -rn 'role="grid"\|role="rowgroup"\|role="gridcell"\|role="table"\|role="treegrid"' design/backlog/ returns nothing. Under plan-rules.md gate 8 (sweep-the-referrers) each straggler is "in this card's scope or a named sibling card — there is no third option"; all three are design/** on one branch prefix in one repo, so they are in scope here. Fixing only backlog.mock.html would have returned 0 from AC 1's grep — reading as complete — while leaving 17 stale sites in the folder the design-reference rule sends the next agent to open first. See the planning bug filed against this miss.

  • design/backlog/backlog.mock.html22 grep hits of <div class="brow" role="row">, three (not four) of them role="row" aria-selected="true" (the multi-select panel), plus the prose at line ~2045: "The row is a role="row" div with sibling controls".
  • design/backlog/backlog-filter.mock.html9 sites across the closed-toolbar and active-filter panels (added at run time).
  • design/backlog/backlog-scale.mock.html8 sites across the virtualized-window and lazy-load panels (added at run time).
  • design/backlog/design-notes.md — line ~152 "A role="row" div with sibling controls" (panel 2), and line ~475 "the issue rows stay role="row" with sibling controls (the 4.2 contract)" (the backlog-filtering section's a11y list).

Why the asset is the thing that is wrong

The asset never specified a grid, a rowgroup, or gridcells — so its role="row" had no parent that could hold it, which is the defect MOTIR-2493 measured as two CRITICAL axe violations on every populated backlog. The half of the annotation that is load-bearing is the sibling-controls / no-nested-interactive contract (nested-interactive, finding #35), and that survives verbatim under listitem; only the role token is stale.

Acceptance criteria

  • grep -c 'role="row"' design/backlog/*.mock.html returns 0 for every one of the three files (amended: was scoped to backlog.mock.html alone), and every one of those rows reads role="listitem" — the mock's rows sit inside the panel container that stands in for the role="list" viewport, so the mock's own markup composes the way the shipped page now does. In backlog-scale.mock.html the role goes on the bounded .vp viewport, matching where the shipped role lives, with the inner flex container left role-less.
  • The three aria-selected="true" rows in the multi-select panel express selection the way the app does — the checked checkbox + the selection tint — with no aria-selected left on a listitem. The .row-check buttons become role="checkbox" aria-checked with a Select / Deselect <key> label, which is the accessible channel the shipped page uses once aria-selected is gone.
  • (added at run time) The two DragOverlay clones in backlog.mock.html do NOT become listitems — they are portalled outside the viewport, so per shipped they drop the role, their wrapper is aria-hidden, and nothing focusable is left inside it.
  • design/backlog/design-notes.md panel 2 and the backlog-filtering a11y bullet both name role="listitem" inside the role="list" viewport, KEEP the sibling-controls / no-nested-interactive contract as the point of the sentence, and state aria-posinset/aria-setsize against the aggregate count (the virtualized list's set size, not the mounted window).
  • The notes record WHY the list arm was chosen over grid — a grid obliges the arrow-key cell keyboard model and gridcell per slot, which the backlog does not implement — so the next reader does not re-open a settled decision.
  • design/backlog/backlog.png is re-exported from the edited mock … even though a role attribute changes no pixels. AMENDED (rung 2): re-exported only where pixels actually change. backlog.png IS re-exported — its legend prose changed. backlog-filter.png / backlog-scale.png are NOT: rendering each mock before and after the edit produces byte-identical PNGs, which proves the attribute-only edits move no pixels — a stronger check than re-exporting. Re-exporting them anyway would have committed pure reflow noise, because this box's sans fallback differs from the original export box (the asset's -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto stack exists on neither, and re-rendering the unedited backlog.mock.html here gives 2480×9078 against the committed 2480×9326). Recorded so the next run does not read the identical PNGs as a skipped step.
  • The role="row" annotations elsewhere in the file that describe a REAL grid are untouched — check before a blanket replace. (Verified: there are none — the folder contains no grid/rowgroup/gridcell/table/treegrid at all.)
  • The design-asset guard lane (pnpm vitest run --config vitest.design.config.ts) is green — the one CI lane a design/* branch does not skip.

Context refs

  • design/backlog/backlog.mock.html — the 22 grep hits + the prose at ~2045.
  • design/backlog/backlog-filter.mock.html, design/backlog/backlog-scale.mock.html — the 17 sites the original measurement missed.
  • design/backlog/design-notes.md — lines ~152 and ~475.
  • app/(authed)/backlog/_components/BacklogRow.tsx — the shipped ARIA comment MOTIR-2493 added, which is the spec this asset must match. It says so itself: "the asset's own role="row" annotation is stale and is corrected by its own design card."
  • app/(authed)/backlog/_components/BacklogList.tsx — the role="list" viewport and why the role stays on it.
  • tests/e2e/shell-a11y-wide.spec.ts — the zero-exclusion /backlog sweep that holds the shipped side.