<!-- source: openspec/changes/add-muse-translation-mode/tasks.md -->

# Tasks — add-muse-translation-mode

> Companion to proposal.md + design.md.

> **⚠ Schema-rename overlay — RAP-1170 (Wave 1, 2026-05-22).** When this change executes, target the post-rename schema: `ideas` (was `canvas_sessions`), `messages` (was `canvas_messages`), `files` (was `canvas_files`), `spec_invitees` (was `canvas_invitees`). The DB substrate columns this change requires (`messages.source_locale`, `messages.translated_content`, `ideas.translation_enabled`) were carried through the rearchitect migration — see `supabase/migrations/20260522120000_rearchitect_spec_document_model.sql`; no new migration is needed in Phase 1. The pre-rename names below are preserved for drafting context per the overlay note in `proposal.md`.

## Wave 1 — Scaffold

- [x] Author `proposal.md`.
- [x] Author `design.md` with D-MTM-1..7.
- [x] Author `tasks.md` (this file).
- [x] Author `verification.md`.

## Wave 2 — DB migration

- [x] **No new migration required in Phase 1.** The substrate columns landed in the rearchitect-spec-document-model migration (`supabase/migrations/20260522120000_rearchitect_spec_document_model.sql`) under the post-rename `messages` table (`source_locale text` + `translated_content jsonb`) and the `ideas` table (`translation_enabled boolean not null default false`). Auto-generated types in `packages/db/src/types.ts` already carry the columns. Verified 2026-05-25 during Phase 1 execution.

## Wave 3 — Muse intent

- [x] `packages/muse/src/modes/architect/translation.ts` — `runArchitectTranslation` standalone runner per D-MTM-1 (chosen over a tool-loop intent branch because translation is a pure-transform, not artifact-emission, and shares no machinery with the architect tool loop).
- [x] System-prompt template with brand-vocabulary forcing block per D-MTM-5 (`composeTranslationSystemPrompt` + `renderVocabularyBlock`).
- [x] `TRANSLATION_LOCALES = ['ru', 'en', 'ro'] as const` + `TRANSLATION_LANGUAGE_NAMES` per D-MTM-7.
- [x] Unit tests in `packages/muse/src/modes/architect/translation.test.ts` (26 cases) — pure helpers + runner guards + mocked Anthropic round-trip + HE/FR rejection.

## Wave 4 — Chat surface

- [x] `packages/ui/src/components/chat/composition/MessageTranslationToggle.tsx` — per-message disclosure widget rendering "Show in <locale>" per D-MTM-2; stateless, parent-driven `showTranslated` + `onToggle`. Unit tests in `packages/ui/__tests__/components/message-translation-toggle.test.tsx` (7 cases).
- [x] `apps/studio/src/app/(auth-walled)/(spec)/spec/[id]/translate-message-actions.ts` — `translateMessageAction` server action that gates on `ideas.translation_enabled`, short-circuits on cache hit (D-MTM-3 immutability), calls `runArchitectTranslation`, and writes `messages.translated_content[<locale>]`.
- [x] Loader + types — `IdeaSession.translationEnabled` and `MessageRow.sourceLocale` + `MessageRow.translatedContent` threaded through `loaders.ts → types.ts` so the follow-up adapter wave has the read-only data it needs.
- [ ] **Deferred follow-up PR (turn-route owned by sibling agent on RAP-1132 `add-specialist-tool-composition`):** wire the toggle through `canvas-chat-adapter.ts` into per-message `blocks`; populate `messages.source_locale` on write in `turn/route.ts`; render the empty-state hint described in the original plan.

## Wave 5 — Brand vocabulary integration

- [ ] `packages/muse/src/modes/architect/intents/translation-vocab.ts` — reads `openspec/brands/<slug>/identity.md § Vocabulary` and injects bullet lines into the system prompt per D-MTM-5.
- [ ] Empty-vocabulary fallback: prompt gracefully renders the section as "(no brand-specific vocabulary)".
- [ ] Unit test: vocabulary bullets are forced-respected across translations; LLM-default rendering does not override.

## Wave 6 — Settings + opt-in flag

- [ ] Canvas settings UI adds a "Translation mode" toggle bound to `canvas_sessions.translation_enabled` per D-MTM-6.
- [ ] Server action `set-translation-enabled` writes the flag + emits an `audit_log` row.
- [ ] Existing canvases remain default-off; no backfill.

## Wave 7 — Gates

- [ ] `pnpm --filter @rapoport-studio/muse lint` exits 0.
- [ ] `pnpm --filter @rapoport-studio/muse test` exits 0.
- [ ] `pnpm --filter @rapoport-studio/ui test` exits 0.
- [ ] `pnpm --filter studio test` exits 0.
- [ ] `pnpm typecheck` exits 0.
- [ ] Local smoke: send a RU turn + an EN turn in a translation-enabled canvas; both reconcile through the toggle; `translated_content` populates lazily; `audit_log` row written on settings toggle.

## Wave 8 — PR + ratification

- [ ] Open PR titled `RAP-1131: add Muse translation mode (chat-as-translation-medium)`.

## Wave 9 — Archive amendments

- [ ] Amend `openspec/current/canvas.md` § chat-message contract: cite the `source_locale` + `translated_content` columns and the translation semantics.
- [ ] Amend `openspec/current/muse.md` (or wherever the Muse intent union lives): add `'translation'` to the intent union.
- [ ] Move `openspec/changes/add-muse-translation-mode/` to `openspec/archive/<YYYY-MM-DD>-add-muse-translation-mode/`.
