MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-140

2.7 Work-item type + executor

Done
Description

Promote two pieces of planning metadata from PROSE to STRUCTURE: a work-item type (what KIND of work — code / design / test / content / research / review / decision / deploy / manual / chore) and an executor (WHO does it — coding_agent or human). Today the plan-seed loader stringifies these into each leaf’s description ("Type: code", "Executor: coding_agent"); this story makes them real work_item fields with a picker, a filter facet, and a type→executor default map.

The model (locked — see the module header for the full rationale):

  • type — a FIXED WorkItemType enum (ten members), DISTINCT from kind, carried only on executable LEAVES (task / subtask / bug). NULLABLE: every epic/story row + every legacy row stays null. Fixed (not free text) so Story 7.6’s per-type prompt generator is a TOTAL function over it and the filter facet is a closed set.
  • executorcoding_agent | human, with a type→executor DEFAULT (code/test/deploy → coding_agent; manual/decision/review → human; design/content/research/chore → either, default coding_agent), seeded when a type is first chosen and OVERRIDABLE.
  • The justified deviation from the Jira mirror (Principle #11). Jira’s issue type IS the kind hierarchy (epic/story/task/sub-task/bug) and routes WHO executes via the assignee field (an AI agent "shows up as an assignee"). Motir splits the axes — type (what work) + executor (who) — for one concrete use case: the Epic-7 AI dispatch layer routes by type (prompt template) and executor (agent-dispatch vs human-assign). Recorded in 2.7.2.

Scope: the picker design under design/work-items/ (2.7.1); the taxonomy + default-map decision (2.7.2); the schema — enum + nullable column + executor field + migration + the default helper (2.7.3); the picker UI on the create modal + detail rail (2.7.4); the seed-loader mapping that stops emitting type/executor as prose (2.7.5); the Epic-6 FilterAST type facet (2.7.6); vitest (2.7.7); and the create-typed-item + filter-by-type E2E (2.7.8).

Out of scope (named so they land where they belong): the per-type PROMPT generation that keys off type (Story 7.6); the AI dispatch surface that routes by executor (Story 7.6 / 7.7); any change to the kind-parent grammar (type is orthogonal to kind and never affects parenting).

Verification

  • Pull the Story branch; run pnpm prisma migrate dev (clean — the new enum + nullable column + executor field apply with no drift) and pnpm db:seed.
  • The seed is now structured (the loader bridge). After re-seeding, open a few PROD leaves: the type + executor are rendered as CHIPS from the structured fields, and the description body NO LONGER contains the "Type:" / "Executor:" prose lines (2.7.5 stopped emitting them). Epics and stories show NO type chip (type is leaf-only → null there).
  • Create-modal + detail picker (the design-gated UI). Open the issue create modal: the type picker offers exactly the ten taxonomy members with their per-type hue (the --el-type-*/IssueTypeIcon treatment), and choosing a type SEEDS the executor per the default map (e.g. picking code selects coding_agent; picking manual selects human), still OVERRIDABLE. Create a code/coding_agent task and a manual/human one; on the detail rail the type chip + executor indicator render and are editable inline. A type override persists; a kind that is epic/story shows no type control.
  • Filter by type (Epic-6 integration). On /issues, the filter builder now offers type as a facet over the shipped 6.1.1 FilterAST; filtering type = manual returns exactly the manual leaves, and type = code OR type = test composes; a saved view round-trips the type predicate.
  • pnpm test — 2.7.7 covers: the type→executor default helper for every enum member; the schema (enum values, type nullable, leaf-only enforcement); the picker default-seeding + override; the loader mapping (structured fields set, prose absent); and the FilterAST type predicate round-trip. New service/repo code respects the per-file coverage gate (motir-core/CLAUDE.md § coverage).
  • The mirror deviation is honest. Confirm 2.7.2’s decision records the verified Jira mirror (issue-type = kind; executor routing = assignee, NOT a sub-type) and the concrete Epic-7-dispatch justification — the Principle-#11 paper trail.
  • If every step holds, approve and merge the Story PR. If anything fails, comment with what didn’t work and Motir will produce a follow-up Subtask under the same Story.