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

The coding-convention four — the ONE row in this story that would LOOSEN a gate, decided rather than swept along

Every other card in this story takes capability away. This one would GIVE it, and that is the whole reason it is not folded into a sibling.

Four operations — /api/ai/coding-convention/audit, /audit-coverage, /convention and /refresh — are gated assertCanManage today, i.e. admin-only: aiConventionService.getAudit, getConvention and reaudit each assert it (they are the three methods whose inline object-type parameter hid the gate from the guard until the extractor repair). The inventory maps all four to ai:plan, which the decision puts at member. Applying the mapping mechanically would widen admin-only operations to every member — including /refresh, which re-runs an audit and therefore spends credits.

The card implements whichever answer the decision recorded, and refuses to guess. The decision's own acceptance criteria require it to settle this explicitly, so this card reads it and does one of exactly two things:

  • The mapping is wrong → the four rows are corrected to ai:configure (the admin key MOTIR-2300 already wired for the AI settings write), the existing assertCanManage calls become assertPermission(…, 'ai:configure'), and nobody's capability moves.
  • The widening is intended → the three asserts become assertPermission(…, 'ai:plan'), the ungated auditCoverageService.getCoverage gains one too, and the PR body states in one sentence which actors gained what.

Either way the fourth operation is not left as it is: /audit-coverage reaches its gate only through a sibling call today.

Acceptance criteria

  • All four operations assert the SAME key, chosen by docs/decisions/member-facing-permissions.md, and the PR body quotes the sentence it was chosen from.
  • If the outcome is ai:configure, the inventory's four rows are corrected and the correction is annotated as a mapping fix rather than a policy change.
  • If the outcome is ai:plan, a test asserts a project member now passes where they were previously refused — a widening that no test proves is a widening nobody reviewed.
  • auditCoverageService.getCoverage asserts the chosen key directly rather than relying on a sibling call.
  • No enforcement flag is flipped here: ai:configure is already enforced, and ai:plan belongs to the close-out card.
  • The guard's pinned counts are re-derived by running it on this branch.
  • pnpm test tests/permissions/ tests/services/ is green.

Context refs

  • lib/services/aiConventionService.tsgetAudit, getConvention, reaudit, and their assertCanManage calls.
  • lib/services/auditCoverageService.tsgetCoverage, the one with no assert of its own.
  • docs/decisions/member-facing-permissions.md — the sentence that decides this card.
  • ai:configure — the shipped admin key for the AI domain, and the alternative destination for these rows.
  • The role-set seam — the prerequisite if the answer is ai:plan.