evOo-local/docs/PRODUCTION-READINESS.md
Cursor Agent c858cb816c
Phase 3: real code work in evOo (git tools, workspace mount, push policy)
Add git, gh, openssh-client, curl, and sudo to the computer image with a docker
smoke test. Mount deployment-owner project workspacePath at /home/rakazo/project,
align /home/rakazo file paths with shell, and resolve default branch from origin/HEAD.

Inject the owner GitHub token from encrypted deployment settings only into project
computers; enforce branch-only push, block force-push, and require approval before
the first push or gh pr in a run. Add runaway guards (tool fuse and stall pause),
collapse live narration, fix streaming progress merge, DE run strings, and Lead as
the project main Oo name. Fix evo-deploy test flake.

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
2026-10-07 21:41:56 +00:00

195 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# evOo-local production readiness
Audit of user journeys, automated coverage, known defects, and backlog. Scope: web app (`apps/web`), API, shared packages; mobile (`apps/mobile`) noted where CI does not cover it.
## Product surfaces
| Surface | Entry | Locales in CI |
|--------|--------|----------------|
| Desktop web | ≥768px viewport | EN + DE in targeted specs |
| Mobile web | 390×844, touch | EN + DE in targeted specs |
| API / Postgres journeys | `packages/testkit` | EN |
| Mobile native | Expo app | Maestro smoke only (not full matrix) |
## User journey inventory
Legend: **E2E** = Playwright under `apps/web/e2e/`; **Unit** = vitest in app/packages; **PG** = postgres journey in testkit; **Gap** = missing or partial automation.
### First run & onboarding
| Journey | Routes / UI | Desktop E2E | Mobile E2E | Unit/PG | Gaps |
|--------|-------------|-------------|------------|---------|------|
| Sign up | `/sign-up` | `golden`, `first-run-onboarding-ux` | same | auth PG | — |
| Look category & swipe | `/onboarding` emoji step | `onboarding-oo-swipe`, `onboarding-emoji-first` | swipe spec (desktop viewport) | — | Mobile-specific swipe gestures |
| Name Oo | name step | `first-run-onboarding-ux` | partial | — | — |
| Language | language step | `first-run-onboarding-ux`, `ui-locale` | DE skip label | — | — |
| Voice | voice step | `first-run-onboarding-ux`, `voice` | DE voices | — | Offline voice errors (no vendor names in UI) |
| Integrations / scan | optional steps | `onboarding-discovery`, `onboarding-complete` | — | onboarding PG | — |
| Reload mid-onboarding | `/onboarding` | `onboarding-reload-persistence` | same | `onboarding-draft.test` | — |
| Intake cards (focus, goal, rhythm, quiet hours) | `/app/g/…` | `onboarding-intake` | **`onboarding-intake-de`** | onboarding-intake PG | Full DE rhythm/quiet copy in cards (UI localized; server stores locale-aware focus facts) |
| Deep link `/onboarding` while signed in | redirect rules | **`route-deep-link-matrix`** | same | — | — |
### Session & auth
| Journey | Routes | E2E | Gaps |
|--------|--------|-----|------|
| Sign in / out | `/sign-in`, `/` | `auth-lifecycle`, `browser-auth` | Tailscale / cookie edge cases |
| Password reset | `/forgot-password`, `/reset-password` | `auth-lifecycle` | — |
| Session unavailable / retry | `/app` loading | **`session-unavailable`**, `module-recovery` | — |
| Welcome (signed out) | `/` | `smoke`, **`route-deep-link-matrix`** | — |
### Heute (daily brief)
| Journey | Route | E2E | Gaps |
|--------|-------|-----|------|
| Open Heute | `/app/heute` | `heute-brief`, **`mobile-layout-audit`** | — |
| Coach / goals list | Heute UI | `heute-brief` | — |
| Deep link reload | `/app/heute` | **`route-deep-link-matrix`**, **`journey-console-errors`** | — |
### 1:1 & group chat
| Journey | Route | E2E | Gaps |
|--------|-------|-----|------|
| Main conversation | `/app/g/:groupId` | `main-conversation`, `first-conversation` | — |
| Bot thread | `/app/:botId` | many specs | — |
| Send message | composer | `message-send` | — |
| Streaming / progress | transcript | `chat-progress-messages`, `chat-queued-progress` | Real LLM latency (mocked) |
| Queued / slow model UI | composer + transcript | `chat-queued-progress` | Multi-run queue depth |
| Errors & retry | composer banner | `run-failure`, `computer-screen-error` | — |
| Stop run | composer | `golden` | — |
| Peer / group | `/app/g/…` | `group-chats`, `peer-messages` | — |
| Console cleanliness | main paths | **`journey-console-errors`** (full route + settings matrix) | — |
### Oos (bots)
| Journey | E2E | Gaps |
|--------|-----|------|
| Create / name / archive / delete | `bot-crud`, `new-bot-ux` | — |
| Switch bot / sidebar | `sidebar-nav`, `unterhaltungen-sidebar` | — |
| Avatar / look | `oo-avatar`, `look-suggestion` | — |
| Capabilities | `bot-capabilities` | — |
| Team vs dedicated computer | `team-computer` | Real docker teardown in PG |
### Projekte
| Journey | E2E | Gaps |
|--------|-----|------|
| Create project space | `spaces`, `adaptive-workspace` | — |
| Bind folder + git | `project-main-agent` | — |
| Timeline / goals | `project-main-agent` | Voice-first goal card |
| Empty project | **`empty-project-state`** | — |
### Settings
| Journey | E2E | Gaps |
|--------|-----|------|
| General / account | `settings-shell`, `user-profile` | — |
| Language (UI locale) | `ui-locale` | — |
| Voice | `voice`, `media-settings` | — |
| Goal / intake copy (DE) | **`onboarding-intake-de`** (focus fact in profile) | Extend locale matrix beyond DE |
| Privacy / delete account | `settings-privacy` | — |
| Model connection | `model-settings`, `models-managed` | Offline model banner |
| Notifications / quiet hours | `notification-settings` | — |
| Messaging | `messaging-settings` | — |
### Account & space deletion
| Journey | E2E / PG | Gaps |
|--------|----------|------|
| Delete account (API) | PG journey 11, **`account-delete-sandbox.postgres`** | — |
| Delete empty space | authorization PG | — |
### Empty, error, offline
| Journey | Coverage | Gaps |
|--------|------------|------|
| No model connected | `model-settings`, composer banner | — |
| Server unreachable | **`session-unavailable`** | — |
| Empty inbox / no bots | partial | — |
| Teaching blocks composer | **`teaching-composer`** | — |
### Navigation, keyboard, a11y
| Journey | E2E | Gaps |
|--------|-----|------|
| Escape closes mobile drawer | `first-run-onboarding-ux` mobile | — |
| Command palette | `command-palette` | — |
| Mention picker keyboard | `mention-picker-keyboard` | — |
| Collapsible sidebar | `collapsible-sidebar-sections`, `mobile-sidebar-swipe` | — |
| Mobile 390px overflow | **`mobile-layout-audit`** | Broader route list |
| Touch targets ≥44px | **`mobile-layout-audit`** | Broader control list |
| Focus management on drawer close | mobile esc test | Broader focus trap review |
### Integrations & MCP
| Journey | E2E | Gaps |
|--------|-----|------|
| Integration setup | `integration-setup` | — |
| MCP OAuth callback | `mcp-oauth` | — |
| GraphQL integrations | `graphql-integrations` | — |
## Prioritized defect list
Severity: **P0** ship blocker · **P1** major UX/trust · **P2** polish · **P3** nice-to-have
### Fixed in Phase 1 ([PR #175](https://github.com/cynarAI/evOo-local/pull/175))
| ID | Sev | Issue | Fix |
|----|-----|-------|-----|
| PR1-1 | P1 | Reload during onboarding lost look/name/step | Session draft via `onboarding-draft.ts` |
| PR1-2 | P1 | DE UI: goal placeholder / discovery “Chief of Staff” English | Lingui for discovery; intake DE E2E |
| PR1-3 | P1 | Account delete left team sandbox + homes | Scoped `destroySpaceSandboxes` on account delete |
| PR1-4 | P1 | Chat felt idle while queued / slow send | Composer `sending`+run chrome; queued label; 120s watchdog |
| PR1-5 | P2 | Console errors on main journeys | Initial `journey-console-errors` spec |
### Fixed in Phase 2 (this PR)
| ID | Sev | Issue | Fix |
|----|-----|-------|-----|
| R2-1 | P1 | Profile focus fact values stored in English for DE users | `focusFactValue()` in `onboarding-intake.ts`; DE assertion in `onboarding-intake-de` |
| R2-2 | P1 | PG journey: account delete sandbox/home teardown | Phase 1 `account-delete-sandbox.postgres` + journey 11 |
| R2-3 | P2 | Persona-test console/network errors | Extended `journey-console-errors` + deep-link matrix; benign React Router / source-map filtering |
| R2-4 | P2 | 390px layout overflow | Heute header wrap; shell safe-area; **`mobile-layout-audit`** |
| R2-5 | P2 | Touch targets &lt;44px | `rk-touch-target` on mobile nav/back; **`mobile-layout-audit`** |
| R2-6 | P2 | Deep link / reload matrix | **`route-deep-link-matrix`** |
| R2-7 | P2 | Empty project / SessionUnavailable / teaching composer E2E | **`empty-project-state`**, **`session-unavailable`**, **`teaching-composer`** |
### Fixed in Phase 3 (real code work)
| ID | Sev | Issue | Fix |
|----|-----|-------|-----|
| R3-git | P0 | Computer image missing git/gh/ssh/curl/sudo | `infra/sandboxes/computer/Dockerfile` + `computer-image-tools.test.sh` |
| R3-mount | P0 | `Space.workspacePath` not mounted in Oo | Bind at `/home/rakazo/project` for deployment owner project spaces |
| R3-path | P0 | `/home/rakazo/...` file paths doubled | `stripVirtualWorkspaceRoot` + tests |
| R3-branch | P0 | Default branch from checkout not remote | `readGitCheckout` uses `origin/HEAD` |
| R3-push | P0 | Unrestricted git push / force-push | `git-shell-policy.ts` + approval for first push/`gh pr` |
| R3-token | P0 | No owner GitHub credential path | Encrypted `ownerGithubTokenCipher` + `deployment.update` (write-only) |
| R3-runaway | P1 | Runaway tool loops | Default 48 tool fuse → `need-user` ask; 15m stall ask |
| R3-ux | P1 | Narration flood / stream fragments | Activity line + streaming text merge in `progressMessageText` |
| R3-i18n | P2 | English run chrome in DE | Lingui for awareness strip + working narration |
| R3-name | P2 | Duplicate “Chief” in project sidebar | Project main Oo defaults to **Lead** |
| R3-flake | P1 | `evo-deploy.test.ts` grep flake | Fixed `--filter` pattern in stack fixture |
**Evo ops:** Rebuild `rakazo/computer:local` on Evo after merge (`pnpm sandbox:build` or compose `computer-image` target). Server deploy via `ops/evo-deploy/deploy.sh` updates app images; the computer image is separate—rebuild and restart sandboxes so new containers pick up git tools.
**Security (GitHub token):** Token is stored only as ciphertext in `deployment_settings.ownerGithubTokenCipher`, set by the deployment owner through `deployment.update`. It is injected as `GITHUB_TOKEN`/`GH_TOKEN` only for the owner’s runs in non-default (project) spaces—not baked into the image or repo. Push/PR policy is enforced in the shell tool layer regardless of token presence.
### Remaining — Phase 3+
| ID | Sev | Issue | Notes |
|----|-----|-------|-------|
| R3-1 | P2 | Offline / model-not-connected on mobile web | Dedicated E2E with RPC fixtures |
| R3-2 | P2 | Intake card rhythm/quiet option labels server-side for non-EN history | Cards localized in web; stored English option labels for agent history |
| R3-3 | P3 | Mobile native parity for onboarding reload | Expo secure store draft |
| R3-4 | P3 | Intake card English questions in non-EN tests | Extend locale matrix beyond DE |
| R3-5 | P3 | NPS/SUS follow-ups from persona round 2 | Product research, not CI |
| R3-6 | P3 | Tailscale / exotic auth cookie edge cases | Manual / staging |
## CI gates (Product)
Lint · Typecheck · Unit · Postgres journeys · Production builds · Web E2E (Playwright). Desktop Electron E2E runs in CI virtual display only.
## How to extend this doc
When adding a journey spec, update the table row and move defects from **Remaining** to **Fixed** with PR link. Keep user-visible copy quoted in PR descriptions when introducing new strings.