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-80Done

2.2.6 Resolve finding #21 — generalize `isReady` + `countOpenBlockers`

Estimate: 10m · Depends on: 2.2.3

Close finding #21 — Story 1.4.4's workItemsService.isReady + workItemLinkRepository.countOpenBlockers currently hardcode 'done' as the terminal-status literal. Now that 2.2.3 exposes workflowsService.getTerminalStatusKeys(projectId), swap the literal for the set. The blocker is "open" iff its status is NOT in its project's terminal-key set.

The blocker can live in a DIFFERENT project than the work item being readiness-checked (cross-project blocks are legal in the work_item_link model from 1.4.3). So the resolution uses each blocker's own project's terminal set, not the readiness-check work item's project's set. The repository method takes a typed input shape and resolves terminal sets per project in one batched query — not N+1.

Implementation shape: countOpenBlockers(workItemId, getProjectTerminalSet: (projectId: string) => Promise<Set<string>>) stays a repo method — the service layer composes workflowsService.getTerminalStatusKeys in. To avoid N+1, fetch all unique blocker project IDs in one query, then call a batched workflowsService.getTerminalStatusKeysByProjects(projectIds, workspaceId) (new method added on top of 2.2.3) returning Map<projectId, Set<string>> in one round-trip.

Acceptance criteria

  • workItemsService.isReady no longer references the string literal 'done' for terminal classification; uses the per-project terminal-key set.
  • New workflowsService.getTerminalStatusKeysByProjects(projectIds, workspaceId) ships and is used by countOpenBlockers for the batched lookup.
  • Vitest test for the scenario from finding #21: a blocker with status: 'cancelled' in a default-seeded project (where cancelled is category: 'done' out of the box) counts as resolved; if a test recategorizes cancelled to todo in one project's workflow, the same blocker there still counts as blocking — proving the resolution reads each project's live category, not a hardcoded set.
  • Cross-project blocker test: project A and project B both have the default seed; an admin recategorizes cancelled in project B to category: 'todo'; a work item in project A blocked by a cancelled blocker in project B still counts as blocked, while one blocked by a cancelled blocker in project A is ready — the readiness check correctly uses each blocker's own project's terminal set.
  • Performance: one query for blockers, one query for the per-project terminal sets, regardless of how many blocker projects there are (asserted via Prisma query log spy).
  • The previous v1 hardcode + its inline comment removed; finding #21's note in countOpenBlockers + isReady deleted.
  • Finding #21's entry in PRODECT_FINDINGS.md gets a > Resolved: 2.2.6 appended.

Context refs

  • Finding #21 in prodect_plan/PRODECT_FINDINGS.md
  • lib/services/workItemsService.ts — current isReady + its v1 test
  • lib/repositories/workItemLinkRepository.ts — current countOpenBlockers + the literal to remove
  • workflowsService from 2.2.3 — extend with the batched method