6.15.5 Quick-filter Work type facet — add the WorkItemType facet to the shared IssueFilterBar (facet state + facet→AST + i18n); the board + /issues both reuse it
Estimate: 30m · Depends on: 6.15.1
Add the Work type facet the quick filter is missing. The shipped quick-filter popover (IssueFilterBar) exposes text · kind · status · assignee; the WorkItemType field (type) is fully DEFINED + COMPILED in the 6.1 registry (enumField('type', 'type-select', { nullable: true, valueWhitelist: WORK_ITEM_TYPES })) and is reachable via the [Advanced] builder — but NOT as a quick facet, so a user cannot filter by Work type from the popover. Add the facet to the SHARED component (the board and the /issues navigator both gain it). No grammar/registry/compiler change and no board-read change — type already compiles; this is purely the quick-filter facet + its state + the facet→AST conversion.
Facet state (lib/issues/issueListFilter.ts): add types: WorkItemType[] (+ an includeUntyped flag for the registry’s nullable empty bucket) to the IssueFilter shape, mirroring kinds/statuses — the DEFAULT value, the toggleType helper, and the IssueFilterParams URL round-trip (encode/decode), so the facet is shareable + reload-safe.
Facet UI (app/(authed)/issues/_components/IssueFilterBar.tsx): add the Work type group between Kind and Status per the 6.15.1 design — a role="listbox" aria-multiselectable of the 10 WORK_ITEM_TYPES (leading glyph = WorkItemTypeIcon in the --el-type-* hue, label labels.workItemType.*, trailing accent Check) + the Untyped row (the IS-NULL bucket). The active-count badge + the applied summary chips include the Work type values.
Facet→AST (lib/filters/ast.ts facetFilterToAst): push a { field: 'type', operator: 'is_any_of', value } condition from the selected types, and map the Untyped selection to the registry’s empty-bucket token (the same is_empty pattern assignee’s Unassigned uses) so the basic→advanced upgrade stays lossless. i18n en + zh (the labels.workItemType.* keys exist; add the facet group label, e.g. filterWorkType).
Acceptance criteria
- The quick-filter popover shows a Work type facet (the 10 types + Untyped); selecting types narrows the read to matching work types; the facet round-trips through the URL/params (reload-safe) and feeds the active-count badge + applied chips.
facetFilterToAstemits thetypeis_any_ofcondition (and maps Untyped → the empty-bucket operator); the basic→advanced upgrade drops no condition (lossless), proven by a unit test over the new facet.- NO change to the filter grammar/registry/compiler or the board read (they already support
type); matches the 6.15.1 design (reusesWorkItemTypeIcon— no hand-rolled UI); colour via--el-*, shape via element-semantic tokens; axe-clean; en + zh; component + unit tests;pnpm test:coverage≥ 90% on changed files.
Context refs
design/boards/board-filter.mock.html(6.15.1 — the Work type facet layout, panel 1) +design/boards/design-notes.md(the "NET-NEW in 6.15 — the Work type facet" note)app/(authed)/issues/_components/IssueFilterBar.tsx(the popover to extend) +lib/issues/issueListFilter.ts(theIssueFilterfacet state + the param round-trip)lib/filters/ast.ts(facetFilterToAst) +lib/filters/registry.ts(thetypefield def — already complete) +lib/issues/executorDefaults.ts(WORK_ITEM_TYPES)lib/issues/workItemTypeMeta.ts(WORK_ITEM_TYPE_META— glyph + hue) +components/issues/WorkItemTypeIcon.tsxmessages/en.json+messages/zh.json(labels.workItemType.*+ the newfilterWorkTypegroup label);motir-core/CLAUDE.md(4-layer; colour/shape tokens)