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

The unconfirmed gates (1/2) — the nine work-item, watcher and mention paths the inventory calls `existing` and the walk cannot see

Half of the guard's CLAIMED_BUT_UNVERIFIED bucket: operations the inventory labels existing"already governed by a shipped predicate" — that its static walk cannot confirm. The guard says the disagreement is the finding and asks for one human read each.

Read the inventory's own Gate today column before starting, because it already answers most of this and the answer is not reassuring:

OperationGate today (per the inventory)Claimed permission
/api/work-items/[id]/acceptance-evidence— none —work_item:edit
/api/work-items/[id]/acceptance-evidence/upload-token— none —work_item:edit
/api/work-items/[id]/estimateworkspace onlywork_item:edit
/api/work-items/[id]/activity/historyworkspace onlyproject:browse
/api/work-items/[id]/rollupworkspace onlyproject:browse
/api/work-items/mention-searchworkspace onlyproject:browse
/api/work-items/[id]/watchworkspace onlywatcher:manage
/api/work-items/[id]/watchersworkspace onlywatcher:manage
/api/work-items/[id]/watchers/[userId]workspace onlywatcher:manage

"Workspace only" means the operation checks that the caller is in the workspace and never asks about the project — which is not the permission the row claims. So the expected outcome of this card is gates, not annotations. Two rows are labelled existing while the same row says the gate is — none —, which is a contradiction inside one line of a done document; the estimate write is a work-item mutation reachable by any workspace member on any project.

What each read ends in — exactly one of two places

  1. The gate is real and the walk cannot follow it — record HOW it is reached in the row (the hop, by name), and teach the walk to see it so the operation leaves the bucket honestly rather than by exemption.
  2. The gate is not there — that is a hole, and the fix is the gate: projectAccessService.assertPermission(projectId, ctx, <the row's key>) in the service, with the project resolved from the work item.

A third option — leaving it as it is with a note — is not available: the whole bucket exists because "we could not tell" was recorded once already.

Acceptance criteria

  • All nine operations are read, and each one's disposition is written into its inventory row: either the named hop that reaches the gate, or the gate this card added.
  • Every operation that turns out to be ungoverned asserts its row's permission, resolved from the work item rather than the actor's active project, with a unit test per gate.
  • The two acceptance-evidence rows in particular end with a real gate or a named hop — an upload-token minter reachable with a session alone is the sharpest item in the list, and the PR body says explicitly what it found.
  • Where a gate was real but invisible, tests/permissions/noUngovernedOperation.test.ts's walk is extended to see it, with the same both-halves control the file already uses for its two earlier repairs: a positive case AND a case that must still read as ungated.
  • The guard's CLAIMED_BUT_UNVERIFIED pin is re-derived by running it on this branch and falls by exactly these nine.
  • pnpm test tests/permissions/ tests/services/ is green.

Context refs

  • tests/permissions/noUngovernedOperation.test.ts — the CLAIMED_BUT_UNVERIFIED set, and the walk's two documented blind spots (extractor, name whitelist) as the model for any third repair.
  • docs/decisions/permission-inventory.md — the nine rows and their Gate today column.
  • lib/services/workItemsService.ts, lib/services/watchersService.ts — the likely homes of the missing asserts.
  • lib/services/projectAccessService.tsassertPermission, getWatcherCapabilities.
  • The no-ungoverned-operation guard — the card that named this bucket and handed it here.