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-3554

(motir-core) Integration vitest through the real MCP transport — a global row reinforced across the boundary, and a retired one that stays retired

Done
Description

The one dedicated test card this parent earns. Every code card above ships its own unit floor (code + tests are one deliverable), so this card asserts only what those suites mock away: the cross-boundary seam, driven through the real MCP transport, exactly as MOTIR-3481 does for search_lessons.

What to assert — and only this

  • The round trip. search_lessons returns a ranked lesson; its id — taken from the STRUCTURED payload, not parsed out of the prose — is passed straight to reinforce_lesson, and the lesson's lastOccurredAt advances. This is the loop the parent exists to close, asserted end to end in one test.
  • A GLOBAL row reinforces across the boundary. The unit suites in motir-ai assert the resolver; this asserts that nothing between the MCP tool and the store narrows it back to tenant-only — the failure mode a per-repo suite structurally cannot see.
  • The gate is upstream of the boundary. A caller without lesson:reinforce is refused and motir-ai is never called. Assert the refusal AND the absence of the upstream call.
  • A CLI-minted token can reinforce and cannot retire — the grant split, through the transport that actually carries it.
  • A replay is not an error. The same occurrenceRef twice returns success reporting that it did not count, and the counters are unchanged. A caller must be able to tell recorded from already recorded without reading an exception.
  • An outage is not a miss. motir-ai unreachable surfaces as a distinguishable failure, never as a silent success — the same outcome-style discipline search_lessons established, where two empty answers that mean opposite things must stay distinguishable.

What NOT to assert

Do not re-derive the ledger's idempotency, the retired-row behaviour, or the generator's marker logic. Those are asserted in the motir-ai cards that ship them, and re-covering them here buys a second place for them to drift. If a clause of this card can be discharged inside one repository, it belongs in that repository's card.

Acceptance criteria

  • A suite drives search_lessonsreinforce_lesson through the real MCP transport and asserts the clock advanced on the returned lesson.
  • The global-scope round trip is asserted through the transport.
  • The permission refusal is asserted to happen BEFORE the upstream call, with the upstream asserted un-called.
  • The CLI-token grant split is asserted: reinforce succeeds, retire is refused.
  • A replay returns success, reports it did not count, and leaves the counters unchanged.
  • An upstream outage is distinguishable from a successful reinforce at the tool's return value.
  • No assertion in this file duplicates one shipped by a motir-ai card; the PR body says which clauses were dropped for that reason.

Context refs

  • MOTIR-3481 — the precedent: an integration vitest through the real MCP transport for the sibling read.
  • lib/mcp/tools/searchLessons.ts — the structured channel this test reads the id from.
  • lib/test-lessons-mock.ts — the existing lesson test double to extend rather than replace.
  • MOTIR-3547 (the parent) — the rule, stated once.