Type · design · Repo motir-core · One PR.
Parent · MOTIR-3490 — the defect this unblocks. Why this card exists: motir run MOTIR-3490 reached run.md guard #3 and stopped. MOTIR-3490's acceptance criteria require two pieces of roadmap-canvas UI that design/roadmap/ does not depict — a grouped node on the ROOT level (its ACs 1, 2, 5) and a visible truncated state for the level cap (its AC 3) — and a run may not improvise UI.
What was checked before concluding the design is absent (the design-reference rule's own precondition): design/roadmap/ was listed — 19 .mock.html sheets, each with a .png, plus a 1 286-line design-notes.md. The notes were read and grepped; every .mock.html under design/roadmap/, design/backlog/ and design/triage/ was grepped for defect / truncat / parentless / unparented / +N more. Findings: the notes describe the root level as "the full root level (every epic)" (design-notes.md:507); the one + N more epics tile in the corpus (design-notes.md:200, grid-init.mock.html) belongs to the ONBOARDING init screen's plan-preview cluster, a different surface; triage.mock.html's "Unparented" is the triage inbox's promote-into-backlog popover. No sheet depicts a grouped root node, and none depicts a truncated level.
A THREE-file design asset under design/roadmap/ — a new *.mock.html sheet built from the real design system, its same-basename .png export, and the design-notes.md section that carries the decisions. A NEW surface gets a NEW sheet; do not amend an existing one.
Design against SHIPPED REALITY — render it first. The roadmap canvas is implemented and running: screenshot the real /roadmap root level (or render the real ProjectRoadmapCanvas / WorkItemNode headlessly from their own source with the real globals.css) BEFORE drawing, and compose the sheet from the real shipped components rather than a stylised stand-in. The project's live tree already contains a parentless bug at the root, so the defect is reproducible on the running app.
Each is a choice the code card would otherwise make silently. Every one gets an explicit disposition in design-notes.md, in the numbered-decision style planning-origin-drill uses.
bug node beside the epics, while its fix direction says collapse non-epic rows. story, task and bug are all legal roots (prisma/sql/work_item_triggers.sql:182 — only subtask is refused). Decide whether the group is bugs-only or every non-epic root, and the node's NAME follows: a parentless task inside a node labelled "Defects" is wrong. State the disposition for each of the four kinds.WorkItemNode (container face, kind tile, meter, drill chevron), GhostAnchor, StationCard, and the wide plan-preview cluster. Pick one and say why; name the count copy and its format, and say which token carries its tile, since there is no --el-type-* hue for a node no kind backs.decorative, or a branch. ProjectRoadmapCanvas counts nodes.filter((n) => n.decorative !== true) to ask "does this level offer a CHOICE?" for autoDescendSingleParent (MOTIR-1807 / MOTIR-1824). The planning-origin card is decorative because it is provenance beside the road; a group node holding real work arguably is not. Decide it, and say what a one-epic project's root level does with the group node present.loadLevel intercepts ORIGIN_ID — or by a real fetch. Draw the level: its breadcrumb crumb label, whether each defect keeps the status chip / ready highlight / off-level-blocker treatment it has today, and what the level says when the group is empty.TREE_LEVEL_MAX_TAKE = 200 with DEFAULT_SORT key-ascending discards the HIGHEST keys — the newest epics — with no cursor and no affordance. Draw what the reader sees when a level is truncated: a + N more tile on the canvas, a header count, a paginate control, or a raised cap. countProjectTreeLevel already exists in workItemRepository, so a total is available to draw against. Draw the affordance at the LEVEL, not only at the root, if it is to be general.findProjectTreeLevel's topInSprintMembersSql), so a committed parentless defect IS a root there. Say whether the same group node appears in sprint scope, and what it shows when the group is the only root.design/roadmap/<name>.mock.html exists and is built from the real design system — components/ui/* markup and --el-* element tokens only, no Tier-0 --color-* and no raw rounded-md / p-2 / h-9..png export sits beside it (Playwright chromium, light, deviceScaleFactor: 2, ~1200px — the convention design-notes.md's asset table records for this area).design/roadmap/design-notes.md gains a section for the new sheet: its row in the asset table, and one numbered disposition per decision 1–7 above, each stating what was decided and why. A decision left as "to be resolved by the code card" does not satisfy this.prettier --check is clean over the changed files, and the diff touches design/roadmap/** only.design/roadmap/design-notes.md — the asset table, the node vocabulary, and the numbered-decision style to follow; :507 is the "full root level (every epic)" line this card revises.design/roadmap/planning-origin-drill.mock.html + its notes section — the closest precedent: a SYNTHETIC root node that is a door, with an explicit decision per station and an explicit decorative ruling.design/roadmap/roadmap.mock.html, auto-drill.mock.html, scope-toggle.mock.html — the shipped root level, the auto-descend cases, and the sprint-scope root.components/planning/WorkItemNode.tsx, ProjectRoadmapCanvas.tsx (:478 the decorative count), workItemLevel.tsx (ORIGIN_ID, buildWorkItemLevel), WorkItemRoadmap.tsx (loadLevel's ORIGIN_ID intercept) — the shipped components the sheet composes from.lib/services/workItemsService.ts:828 (TREE_LEVEL_MAX_TAKE) · :3374 (getProjectRoadmap) · lib/issues/issueListView.ts:70 (DEFAULT_SORT) — what the cap does and which rows it drops.lib/repositories/workItemRepository.ts — findProjectTreeLevel (no kind predicate at the root) and countProjectTreeLevel (the total a truncation affordance can draw against).