[2026-10-15] eagle: work/.DS_Store work/projects/macos-cloud-autofix-plan-2026-10-15.md

This commit is contained in:
Alexey Martemyanov committed 2026-10-15 14:33:15 +06:00
1 parent fb5215cabc
commit aa85662551
2 files changed
+189 -189

No files matched your search

BIN
View File
Binary file not shown.
@@ -1,5 +1,5 @@
--- ---
title: 'macOS: cloud flow для автофикса багов и тестов (Claude/Codex) — план' title: 'macOS: cloud flow for automatically fixing and validating bugs and tests (Claude/Codex) — plan'
date: '2026-10-15' date: '2026-10-15'
status: proposal status: proposal
tags: tags:
@@ -11,275 +11,275 @@ tags:
- sentry - sentry
- virfield - virfield
--- ---
# macOS: cloud flow для автоматического фикса и валидации багов и тестов # macOS: cloud flow for automatically fixing and validating bugs and tests
Статус: **предложение**, не реализовано. Собрано 2026-10-15 из: Asana (AI Agent Infrastructure / O-T), Obsidian (Virfield, Personal OS, macos-tests-worktrees-2026-10-14, ci-pipeline), `.github/workflows` и `.claude/skills` в apple-browsers, документации Anthropic / OpenAI / Sentry / Bitrise. Status: **proposal**, not implemented. Compiled on 2026-10-15 from: Asana (AI Agent Infrastructure / O-T), Obsidian (Virfield, Personal OS, macos-tests-worktrees-2026-10-14, ci-pipeline), `.github/workflows` and `.claude/skills` in apple-browsers, and Anthropic / OpenAI / Sentry / Bitrise documentation.
Пометки: ✅ подтверждено источником, ⚠️ не проверено / нужен spike. Legend: ✅ confirmed by a source, ⚠️ not verified / needs a spike.
--- ---
## 1. Что уже есть (чтобы не строить второй раз) ## 1. What already exists (so we don't build it twice)
### 1.1 В Asana (опыт компании) ### 1.1 In Asana (company experience)
| Что | Суть | Урок для нас | | What | Summary | Lesson for us |
|---|---|---| |---|---|---|
| **Windows crash-triage** ([1214714826035263](https://app.asana.com/1/137249556945/task/1214714826035263)) | Prefect job тянет Sentry через MCP → Claude agent → ежедневный stability report → Release DRI. ~$8/день (~$250–500/мес). Сначала Cursor self-hosted, затем Claude на **GitHub-hosted Windows runner**, который Prefect запускает как GHA. Prefect-variable хранит «память» между запусками → дешевеет день ото дня. | Рабочая схема: **pre-fetch в доверенном контуре → artifact → агент на runner'е**. Агент не ходит в Sentry сам. | | **Windows crash triage** ([1214714826035263](https://app.asana.com/1/137249556945/task/1214714826035263)) | A Prefect job pulls Sentry via MCP → Claude agent → daily stability report → Release DRI. ~$8/day (~$250–500/month). Started on Cursor self-hosted, then moved to Claude on a **GitHub-hosted Windows runner** that Prefect triggers as a GHA. A Prefect variable stores "memory" between runs, so cost drops day over day. | A working pattern: **pre-fetch in a trusted zone → artifact → agent on the runner**. The agent does not call Sentry itself. |
| Там же: отношение разработчиков к авто-PR | В апреле авто-PR встретили враждебно («проверять PR дороже, чем идею»). Решение: каждая находка **валидируется unit/UI-тестом-репродьюсером**, отчёт = root cause + направление + тест. После этого 2 AI-PR влились без комментариев, команда согласилась на авто-PR; ~20 CPMN деградации предотвращено. | Нельзя начинать с авто-PR. Лестница доверия: report → proposal → draft PR. **Без failing-теста фикс не предлагается.** | | Same task: developer attitude to auto-PRs | In April auto-PRs were met with hostility ("reviewing a PR costs more than checking the idea"). The fix: every finding is **validated with a unit/UI reproducer test**, and the report is root cause + direction + test. After that 2 AI PRs landed with no review comments, the team agreed to auto-PRs, and ~20 CPMN of degradation was prevented. | Do not start with auto-PRs. Trust ladder: report → proposal → draft PR. **No fix is proposed without a failing test.** |
| **Find an alternative to Cursor Cloud Agents** ([1216757783325568](https://app.asana.com/1/137249556945/project/72649045549333/task/1216757783325568), DRI Chris Clarke) | 3 класса workflow: analyze-and-report / **build-and-fix** / drive-browser. Interactive Claude runners для Android, SERP, generic уже есть (claude.ai/code). Linux/Windows self-hosted GHA runners — в работе ([1218221113915359](https://app.asana.com/1/137249556945/task/1218221113915359)). **macOS — главный пробел**: в Azure нет macOS, поэтому нет пути к внутренней сети (dub, ClickHouse, Sentry). Проект «Provision Mac Machines» ([1215557028847084](https://app.asana.com/1/137249556945/project/1211983163358654/task/1215557028847084), AWS EC2 Mac) — **ON HOLD**. | Мы закрываем именно этот пробел. Нужно встроиться в проект AI Agent Infrastructure, а не делать параллельный. | | **Find an alternative to Cursor Cloud Agents** ([1216757783325568](https://app.asana.com/1/137249556945/project/72649045549333/task/1216757783325568), DRI Chris Clarke) | 3 workflow classes: analyze-and-report / **build-and-fix** / drive-browser. Interactive Claude runners for Android, SERP and generic work already exist (claude.ai/code). Linux/Windows self-hosted GHA runners are in progress ([1218221113915359](https://app.asana.com/1/137249556945/task/1218221113915359)). **macOS is the main gap**: Azure has no macOS, so there is no path to the internal network (dub, ClickHouse, Sentry). The "Provision Mac Machines" project ([1215557028847084](https://app.asana.com/1/137249556945/project/1211983163358654/task/1215557028847084), AWS EC2 Mac) is **ON HOLD**. | We are closing exactly this gap. We need to plug into the AI Agent Infrastructure project rather than run a parallel one. |
| Context transfer PoC ([1217164276206833](https://app.asana.com/1/137249556945/task/1217164276206833)) | GHA run не resumable → в ZIP-artifact кладут transcript + prompt + metadata, skill восстанавливает контекст в новом чате. Предложено стандартизировать как company-wide GHA. | Решает «человек хочет вмешаться» без интерактивных сессий. | | Context-transfer PoC ([1217164276206833](https://app.asana.com/1/137249556945/task/1217164276206833)) | A GHA run is not resumable, so a ZIP artifact holds transcript + prompt + metadata, and a skill restores the context in a new chat. Proposed as a company-wide GHA. | Solves "a human wants to step in" without interactive sessions. |
| **Bitrise** ([1218829288858490](https://app.asana.com/1/137249556945/project/1219113011535833/task/1218829288858490)) | Apple team уже использует **Bitrise как провайдера macOS-раннеров для GHA** (GitHub macOS слишком медленные), 360-мин лимит GHA. Bitrise RDE (remote dev env: SSH/VNC, suspend/resume) в trial: 1 concurrent session, баг Bitrise GitHub App с private repos (Bitrise чинит). | Для автоматических запусков берём то, что уже работает (GHA + Bitrise). RDE — для интерактива. | | **Bitrise** ([1218829288858490](https://app.asana.com/1/137249556945/project/1219113011535833/task/1218829288858490)) | The Apple team already uses **Bitrise as the macOS runner provider for GHA** (GitHub macOS runners are too slow); GHA has a 360-minute cap. Bitrise RDE (remote dev environment: SSH/VNC, suspend/resume) is in trial: 1 concurrent session, and a Bitrise GitHub App bug with private repos (Bitrise is fixing it). | For automated runs use what already works (GHA + Bitrise). RDE is for interactive work. |
| **Security triage Bitrise RDE** ([1219413380003457](https://app.asana.com/1/137249556945/project/1199892415909552/task/1219413380003457), ответ 2026-10-14) | (AT1) прямой доступ Bitrise → внутренние системы **не жизнеспособен** (пришлось бы открывать все пулы Bitrise). (AT2) использовать RDE MCP, локальный Claude — оркестратор; `SSH_AUTH_SOCK` обнулить (forward ключей). (AT3) не auto-approve RDE tools в сессии с ClickHouse/Sentry MCP; всё, что вернулось из RDE, — untrusted. Сами RDE-сессии изолированы. | **Жёсткое ограничение дизайна:** агент на Bitrise-машине не видит Sentry/ClickHouse/dub. Данные приходят артефактом. | | **Security triage: Bitrise RDE** ([1219413380003457](https://app.asana.com/1/137249556945/project/1199892415909552/task/1219413380003457), reply 2026-10-14) | (AT1) Direct access from Bitrise to internal systems is **not viable** (all Bitrise address pools would have to be opened). (AT2) Use the RDE MCP with a local Claude as orchestrator; set `SSH_AUTH_SOCK` to empty (it forwards keys). (AT3) Do not auto-approve RDE tools in a session that also has the ClickHouse/Sentry MCP; anything coming back from RDE is untrusted. RDE sessions themselves are isolated. | **Hard design constraint:** an agent on a Bitrise machine cannot see Sentry/ClickHouse/dub. Data arrives as an artifact. |
| Bug Squisher / Duck.ai | SERP: `[🤖 Bug Squisher]` PR'ы в ddg. Duck.ai: инженер вручную `$auto fix this bug` (порт pstack) → готовый PR → ревью. Автоматизацию добавят после доказанной надёжности. Artur (Chromium): агент не управляет браузером напрямую, а **пишет воспроизводимый journey-скрипт**, который прогоняется на base и fix коммитах — агент не может «соврать» в валидации. | Берём этот приём для валидации (см. §5). Согласовать с flux/pstack, чтобы не плодить 5-й параллельный фреймворк (см. комментарий о пересечениях в [1213572946361338](https://app.asana.com/1/137249556945/project/1209667197557478/task/1213572946361338)). | | Bug Squisher / Duck.ai | SERP: `[🤖 Bug Squisher]` PRs in ddg. Duck.ai: an engineer manually runs `$auto fix this bug` (a pstack port) → a ready PR → review. Automation comes later, once reliability is proven. Artur (Chromium): the agent does not drive the browser directly but **writes a reproducible journey script** that is run on the base and fix commits, so the agent cannot "lie" in validation. | Reuse this trick for validation (see §5). Align with flux/pstack so we don't add a fifth parallel framework (see the overlap comment in [1213572946361338](https://app.asana.com/1/137249556945/project/1209667197557478/task/1213572946361338)). |
| Модель гейтов (из того же обсуждения) | Consensus-гейты (kick-off, tech design, post-mortem) — людям; unattended agent их пропускает. Review-гейты (privacy/security triage, ship review) обязательны — «стекаются» в конец, коррекции возвращают агента в цикл. | Агентский flow = draft PR + обязательные review-гейты, без consensus. | | Gate model (same discussion) | Consensus gates (kick-off, tech design, post-mortem) belong to humans; an unattended agent skips them. Review gates (privacy/security triage, ship review) are mandatory — they stack at the end, and corrections send the agent back into the loop. | Agent flow = draft PR + mandatory review gates, no consensus gates. |
| Windows release quality ([1215834564874913](https://app.asana.com/1/137249556945/task/1215834564874913)) | Windows — пилот; **macOS идёт следом**. Preview ловит краши, но их не превращают в bug с owner'ом («conversion problem»). | Наш flow = «конвертер» crash → воспроизведённый тест → draft PR для macOS. | | Windows release quality ([1215834564874913](https://app.asana.com/1/137249556945/task/1215834564874913)) | Windows is the pilot; **macOS follows**. Preview catches crashes, but they are not turned into bugs with an owner (a "conversion problem"). | Our flow is the "converter" crash → reproduced test → draft PR for macOS. |
⚠️ Отдельной задачи именно про **Android cloud AI bug fixing** в Asana не нашлось — только упоминание, что Claude runners доступны для Android/SERP/generic. Если есть конкретная ссылка, надо дочитать. ⚠️ I found no separate Asana task about **Android cloud AI bug fixing** — only the mention that Claude runners are available for Android/SERP/generic. If there is a specific link, it needs reading.
⚠️ Отдельного «Sentry crash report → Claude cloud» для Apple нет: сегодня это ручной skill `ddg-sentry-report` (пользователь вызывает сам, пишет в Asana). ⚠️ There is no "Sentry crash report → Claude cloud" flow for Apple either: today it is the manual `ddg-sentry-report` skill (the user invokes it, it writes to Asana).
### 1.2 В репозитории apple-browsers ### 1.2 In the apple-browsers repo
- `macos_pr_checks.yml` (unit + integration на `macos-26` / `macos-26-xlarge`, release build, retry), `macos_ui_tests.yml` (matrix по классам × macOS 14/15/26, ночью 03:00 UTC, **`workflow_dispatch` с `single_test_class`**, `user_modes`, `workflow_call`), `macos_run_ui_test.yml`, `macos_build_notarized.yml` (UI-тесты требуют notarized Review app), `danger.yml`, `conflict_watch.yml`, `.github/actions/bitrise-build-cache`, `process-test-results`, `asana-failed-pr-checks`. - `macos_pr_checks.yml` (unit + integration on `macos-26` / `macos-26-xlarge`, release build, retry), `macos_ui_tests.yml` (class × macOS 14/15/26 matrix, nightly 03:00 UTC, **`workflow_dispatch` with `single_test_class`**, `user_modes`, `workflow_call`), `macos_run_ui_test.yml`, `macos_build_notarized.yml` (UI tests need the notarized Review app), `danger.yml`, `conflict_watch.yml`, `.github/actions/bitrise-build-cache`, `process-test-results`, `asana-failed-pr-checks`.
- Skills: `ddg-diagnose-ci-failure` (JUnit XML из артефактов, классификация, flaky vs deterministic, регрессионная timeline), `ddg-sentry-report`. Оба **user-initiated**: трогают Asana → «lethal trifecta» блокирует прочие MCP. - Skills: `ddg-diagnose-ci-failure` (JUnit XML from artifacts, classification, flaky vs deterministic, regression timeline) and `ddg-sentry-report`. Both are **user-initiated**: they touch Asana, so the "lethal trifecta" policy blocks other MCPs afterwards.
- `AGENTS.md`, `CLAUDE.md`, `REVIEW.md` — инструкции уже есть. - `AGENTS.md`, `CLAUDE.md`, `REVIEW.md` already exist.
- `.xcode-version` = 26.4 (ci-pipeline note). У Virfield профиль `uitest-27-v1` = macOS 27 / Xcode 27 → **расхождение**, надо иметь образ под 26.4. - `.xcode-version` = 26.4 (ci-pipeline note). The Virfield profile `uitest-27-v1` = macOS 27 / Xcode 27, so there is a **mismatch**; we need an image for 26.4.
### 1.3 Наши локальные достижения (Obsidian) ### 1.3 Our local achievements (Obsidian)
**Virfield** (Tart + SSH nodes, Go, MCP из 18 tools: `vm_acquire/vm_lease/vm_release/vm_tunnel`, `image_*`): **Virfield** (Tart + SSH nodes, Go, MCP with 18 tools: `vm_acquire/vm_lease/vm_release/vm_tunnel`, `image_*`):
- ✅ Disposable macOS VM по lease, pinned SSH, экспорт артефактов, cleanup; golden Xcode 15.2 / 13.4.1 / 27.0. - ✅ Disposable macOS VM per lease, pinned SSH, artifact export, cleanup; goldens for Xcode 15.2 / 13.4.1 / 27.0.
- ✅ Исправлены вещи, на которых падают DDG UI-тесты: locked keychain (login + default, GUI и SSH контексты), 1920×1080, ASIF/Recovery, SSH banner timeout. Реальный `DownloadsUITests.testDownloadFinishesThenPopupIsShown` — 2 прогона 0 failures (Xcode 27.1 products → guest 27.0). - ✅ Fixed the things DDG UI tests fail on: locked keychain (login + default, GUI and SSH contexts), 1920×1080, ASIF/Recovery, SSH banner timeout. A real `DownloadsUITests.testDownloadFinishesThenPopupIsShown` ran twice with 0 failures (Xcode 27.1 products → guest 27.0).
- ⚠️ Не принято: Broker/Runner → apple-browsers UI suite целиком; установленный `aee89c1` ≠ source `9a740c0`; `vm_drift` ложные срабатывания; admission quirks (storage reserve); **пул = 2 VM на одном Mac**, GitHub CI отложен. Это хорошая **dev/acceptance площадка**, но не production-флот. - ⚠️ Not accepted yet: Broker/Runner → the full apple-browsers UI suite; installed `aee89c1` ≠ source `9a740c0`; false `vm_drift` events; admission quirks (storage reserve); **pool = 2 VMs on one Mac**; GitHub CI deferred. It is a good **dev/acceptance sandbox**, not a production fleet.
**Personal OS / Executor** (3 попытки, 2026-04…10): **Personal OS / Executor** (3 attempts, 2026-04…10):
- Executor v1 (автономный LLM-оркестратор) → **инцидент** (писал в Asana, утечки задач в Discord). Executor v2 (bash runner/analyzer + 5 worker-промптов: queued / in_progress / fix_ci / fix_comments / pr_review; state machine `queued→in_progress→pr→complete/abandoned`; no-output watchdog 30 мин, hard 3 ч; lockfile; фильтры analyzer'а) — реализован, но кроны на паузе. - Executor v1 (autonomous LLM orchestrator) → **incident** (wrote to Asana, task data leaked to Discord). Executor v2 (bash runner/analyzer + 5 worker prompts: queued / in_progress / fix_ci / fix_comments / pr_review; state machine `queued→in_progress→pr→complete/abandoned`; no-output watchdog 30 min, hard limit 3 h; lockfile; analyzer filters) was implemented, but the crons are paused.
- Сквозные уроки: (1) **детерминированный слой работал, агентный — нет**; (2) агенту нельзя писать во внешние системы и иметь канал наружу с рабочими данными; human-in-the-loop — обязательный гейт; (4) слабое железо не тянет агентный стек; (7) провайдер модели — конфиг, не архитектура; Codex bwrap не стартует в Docker; подписочные OAuth-токены не проксировать. - Cross-cutting lessons: (1) **the deterministic layer worked, the agentic one did not**; (2) an agent must not write to external systems or have an outbound channel carrying work data, and human-in-the-loop is a mandatory gate; (4) weak hardware cannot carry an agent stack; (7) the model provider is config, not architecture; Codex bwrap does not start in Docker; do not proxy subscription OAuth tokens.
**Тестовые фиксы 2026-10-14** ([[work/projects/macos-tests-worktrees-2026-10-14]]) — готовый эталон качества и eval-набор: **Test fixes of 2026-10-14** ([[work/projects/macos-tests-worktrees-2026-10-14]]) — a ready quality reference and eval set:
- AddressBarTests: корень = `ensureObjectDeallocated(.interrupt)` шлёт SIGINT при живом объекте; 2 причины (autorelease в `TestRunHelper`, strong `self` в animation completion). Валидация: **main 10/10 FAIL → fix 15/15 PASS**, 7/7 изолированно, полный Integration ×2. - AddressBarTests: root cause = `ensureObjectDeallocated(.interrupt)` sends SIGINT while an object is still alive; two causes (autorelease in `TestRunHelper`, strong `self` in an animation completion). Validation: **main 10/10 FAIL → fix 15/15 PASS**, 7/7 isolated, full Integration ×2.
- Fire Window video leak: **не воспроизведено**, итог = 4 guard-теста без фикса (проверка валидности: намеренная утечка → тест падает). «Не воспроизвелось» — легитимный исход. - Fire Window video leak: **not reproduced**; outcome = 4 guard tests, no fix (validity check: an intentional leak makes the test fail). "Not reproduced" is a legitimate outcome.
- Наблюдения среды: **display sleep** ломает dealloc-проверки (display-link анимации стоят) → VM/раннер должен держать дисплей бодрым; `async` тесты маскируют release; нужны мок сети (OHHTTPStubs) и изоляция настроек пользователя. - Environment observations: **display sleep** breaks dealloc checks (display-link animations stall), so the VM/runner must keep the display awake; `async` tests mask releases; network mocking (OHHTTPStubs) and isolation of user settings are required.
### 1.4 Внешнее (проверено по документации) ### 1.4 External (checked against documentation)
| Платформа | Что умеет | Ограничение для нас | | Platform | What it does | Limitation for us |
|---|---|---| |---|---|---|
| **`anthropics/claude-code-action@v1`** | Automation mode (`prompt`), триггеры: schedule / dispatch / issue / PR; `claude_args` (`--max-turns`, `--allowedTools`, `--model`); skills из `.claude/skills`; auth: API key, OAuth, **OIDC federation (без долгоживущих секретов)**; по умолчанию создаёт ветку, PR — по ссылке (человек жмёт). Коммиты токеном `GITHUB_TOKEN` не запускают CI → нужен GitHub App/custom token. | ⚠️ Документация говорит «runs on GitHub-hosted runners»; работа на macOS/Bitrise-label **явно не описана** → spike. Ничего не мешает использовать `claude -p` напрямую в job. | | **`anthropics/claude-code-action@v1`** | Automation mode (`prompt`); triggers: schedule / dispatch / issue / PR; `claude_args` (`--max-turns`, `--allowedTools`, `--model`); skills from `.claude/skills`; auth: API key, OAuth, **OIDC federation (no long-lived secrets)**; by default creates a branch and the PR is created via a link (a human clicks). Commits made with `GITHUB_TOKEN` do not trigger CI, so a GitHub App/custom token is needed. | ⚠️ The docs say "runs on GitHub-hosted runners"; running on macOS/a Bitrise label is **not explicitly described** → spike. Nothing prevents using `claude -p` directly in a job. |
| **`openai/codex-action@v1`** | `codex exec` в job; **Linux или macOS runner**; `sandbox`, `safety-strategy: drop-sudo`, `allow-users`. | Примеров fix-CI нет (только ревью PR). | | **`openai/codex-action@v1`** | `codex exec` in a job; **Linux or macOS runner**; `sandbox`, `safety-strategy: drop-sudo`, `allow-users`. | No fix-CI examples (only PR review). |
| **Claude Code cloud (claude.ai/code, routines)** | Сессии на VM Anthropic; routines: schedule / **API trigger (`POST /fire`, поле `text` = payload алёрта)** / GitHub events; Auto-fix PR (реагирует на CI failures и комментарии). | Anthropic-VM не собирает Xcode. Лимиты routines: 30 fire/час на routine. `text` оборачивается как untrusted. | | **Claude Code cloud (claude.ai/code, routines)** | Sessions on Anthropic VMs; routines: schedule / **API trigger (`POST /fire`, the `text` field = alert payload)** / GitHub events; Auto-fix PR (reacts to CI failures and comments). | Anthropic VMs do not build Xcode. Routine limits: 30 fires/hour per routine. `text` is wrapped as untrusted. |
| **Claude self-hosted environments** (public beta, Team/Enterprise) | Runner на **нашем** хосте; outbound-only; routines и claude.ai/code роутятся на него; ephemeral runner (`--drain-grace-sec 0` → чистый диск); сессии **resumable с любого устройства**. Runner «лочится» на одного owner'а. | ⚠️ macOS-runner в доках не описан (рецепты — Kubernetes/Compose); Chris Clarke: «supports macOS, but we don't have any provisioned». Спросить Anthropic (в проекте есть похожая подзадача по Windows). | | **Claude self-hosted environments** (public beta, Team/Enterprise) | A runner on **our** host; outbound-only; routines and claude.ai/code route to it; ephemeral runner (`--drain-grace-sec 0` → clean disk); sessions are **resumable from any device**. A runner locks to one owner. | ⚠️ A macOS runner is not described in the docs (recipes are Kubernetes/Compose); Chris Clarke: "supports macOS, but we don't have any provisioned". Ask Anthropic (the project has a similar subtask for Windows). |
| **Sentry Seer** | Автоматический Issue Fix: ≥10 events, активность ≤14 дней, fixability score; уровни: stop after RCA / solution / PR / **hand-off в Claude Agent** (или Cursor, Copilot); Seer **никогда не мерджит**. Рекомендуют начинать с «Stop after Solution». | Не собирает macOS-проект; нужен GitHub integration + code mappings; приватность (крэш-данные → внешний агент) — нужен privacy triage. | | **Sentry Seer** | Automatic Issue Fix: ≥10 events, activity within 14 days, fixability score; levels: stop after RCA / solution / PR / **hand-off to Claude Agent** (or Cursor, Copilot); Seer **never merges**. They recommend starting with "Stop after Solution". | Does not build the macOS project; needs the GitHub integration + code mappings; privacy (crash data → an external agent) needs a privacy triage. |
| **Bitrise Build Hub (GHA)** | `runs-on: <bitrise-label>`, M4 Pro, Xcode в течение 24 ч после релиза, on-demand ephemeral с GitHub App, US/EU. | Нет явных гарантий egress-контроля. | | **Bitrise Build Hub (GHA)** | `runs-on: <bitrise-label>`, M4 Pro, Xcode within 24 h of release, on-demand ephemeral with the GitHub App, US/EU. | No explicit egress-control guarantees. |
| **Bitrise RDE** | SSH/VNC, suspend/resume, MCP server. | См. security triage выше; trial = 1 сессия. | | **Bitrise RDE** | SSH/VNC, suspend/resume, MCP server. | See the security triage above; trial = 1 session. |
| **Bitrise AI Build Fixer** | Анализ упавшего билда → PR → ре-билд (Pro/Enterprise). | ⚠️ Описан для Bitrise CI; для «Build Hub под GHA» не подтверждено. Покрывает только build failures, не flaky/crash. | | **Bitrise AI Build Fixer** | Analyzes a failed build → PR → rebuild (Pro/Enterprise). | ⚠️ Described for Bitrise CI; not confirmed for "Build Hub under GHA". Covers only build failures, not flaky tests or crashes. |
| **Tart / Orchard / Tartelet / Cilicon** | OSS ephemeral macOS VM на Apple silicon для self-hosted GHA runners. | ⚠️ Новость о закрытии Cirrus CI — из блога конкурента, не проверена; Tart OSS от этого не зависит. | | **Tart / Orchard / Tartelet / Cilicon** | OSS ephemeral macOS VMs on Apple silicon for self-hosted GHA runners. | ⚠️ The news about Cirrus CI shutting down comes from a competitor's blog and is unverified; Tart is OSS and does not depend on it. |
--- ---
## 2. Постановка ## 2. Problem statement
**Цель:** по сигналу (упал/флакает тест на main; новый крэш в Sentry; баг) получить **draft PR с доказательствами**, что фикс работает (до: красный N/N, после: зелёный N/N, lint, нужные схемы собираются), либо **обоснованный отказ** («не воспроизведено», «нужен человек»). Человек ревьюит и мерджит. **Goal:** given a signal (a test fails/flakes on main; a new crash in Sentry; a bug), produce a **draft PR with evidence** that the fix works (before: red N/N, after: green N/N, lint, required schemes build), or a **reasoned refusal** ("not reproduced", "needs a human"). A human reviews and merges.
**Не цели:** auto-merge; запись в Asana/чаты самим агентом; фиксы фич/UX без владельца; релизные ветки на первом этапе. **Non-goals:** auto-merge; the agent writing to Asana/chats; fixing features/UX without an owner; release branches in the first stage.
**Классы задач (по возрастанию сложности и риска):** **Task classes (increasing complexity and risk):**
1. Flaky/failing unit & integration test (чистый macOS, без секретов). 1. Flaky/failing unit & integration test (plain macOS, no secrets).
2. Failing UI test (нужен notarized Review build, UITestCase, matrix по OS). 2. Failing UI test (needs the notarized Review build, UITestCase, OS matrix).
3. Crash из Sentry (нужен репродьюсер; данные из внутреннего контура). 3. Crash from Sentry (needs a reproducer; data comes from the internal zone).
4. Bug из Asana (нужны repro steps; наибольший риск prompt injection и архитектурных ошибок). 4. Bug from Asana (needs repro steps; highest prompt-injection risk and risk of architectural mistakes).
--- ---
## 3. Целевая архитектура (общая для всех вариантов) ## 3. Target architecture (shared by all options)
```mermaid ```mermaid
flowchart LR flowchart LR
subgraph Signals[Сигналы] subgraph Signals["Signals"]
A[CI: JUnit из main/ночных runs] A["CI: JUnit from main / nightly runs"]
B[Sentry: new-in-release, >=N events] B["Sentry: new in release, N+ events"]
C[Asana bug / ручной запуск] C["Asana bug / manual trigger"]
end end
subgraph Trusted[Доверенный контур - Linux, есть dub/Sentry] subgraph Trusted["Trusted zone - Linux, has dub and Sentry access"]
D[Детерминированный intake:\nфингерпринт, dedupe, eligibility,\nбюджет, scrub PII] D["Deterministic intake:<br/>fingerprint, dedupe, eligibility,<br/>budget, PII scrub"]
E[signal.json + артефакты] E["signal.json + artifacts"]
end end
subgraph Mac[macOS runner - эфемерный, без внутренней сети] subgraph Mac["macOS runner - ephemeral, no internal network"]
F[Agent job: analyze -> repro -> fix -> validate] F["Agent job: analyze, repro, fix, validate"]
G[evidence bundle:\nxcresult, before/after, summary.json] G["Evidence bundle:<br/>xcresult, before/after, summary.json"]
end end
H[Draft PR ai/fix/fingerprint\nлейбл ai-generated] H["Draft PR ai/fix/fingerprint<br/>label ai-generated"]
I[Существующий PR CI:\nunit+integration+UI на Bitrise] I["Existing PR CI:<br/>unit + integration + UI on Bitrise"]
J[Человек: ревью, мердж] J["Human: review and merge"]
K[Notifier: Mattermost / Asana-комментарий\n(детерминированный, узкий токен)] K["Notifier: Mattermost / Asana comment<br/>deterministic, narrow token"]
A-->D A --> D
B-->D B --> D
C-->D C --> D
D-->E-->F-->G-->H-->I-->J D --> E --> F --> G --> H --> I --> J
H-->K H --> K
I-->|падение CI|F I -->|"CI failure"| F
``` ```
Принципы (из уроков Executor и security triage): Principles (from the Executor lessons and the security triage):
1. **Детерминированный каркас, LLM только в узком worker-шаге.** Очередь, дедуп, бюджет, ретраи, нотификации — код, не агент. 1. **A deterministic skeleton, with the LLM only in a narrow worker step.** Queue, dedupe, budget, retries and notifications are code, not an agent.
2. **Агент не получает ни Asana, ни Sentry, ни ClickHouse.** Вход — файлы (`signal.json`), выход — ветка `ai/fix/<fingerprint>` + `summary.json`. 2. **The agent gets no Asana, Sentry or ClickHouse access.** Input is files (`signal.json`); output is a branch `ai/fix/<fingerprint>` + `summary.json`.
3. **Запись только draft PR в ветку `ai/*`** (GitHub App; ruleset: пушить можно только `ai/*`, `main` закрыт). Нотификации и Asana-комментарии делает отдельный детерминированный шаг. 3. **Write access only as a draft PR on an `ai/*` branch** (GitHub App; ruleset: only `ai/*` may be pushed, `main` is closed). Notifications and Asana comments are done by a separate deterministic step.
4. **Секреты подписи/notarization не в agent-job.** Агентский job гоняет unit/integration без секретов; UI-тесты запускаются **оркестратором** на ветке агента через существующий `macos_run_ui_test` (как для обычного PR). 4. **Signing/notarization secrets are not in the agent job.** The agent job runs unit/integration without secrets; UI tests are launched by the **orchestrator** on the agent's branch through the existing `macos_run_ui_test` (like any human PR).
5. **Провайдер = конфиг:** `agent: claude|codex`, один prompt/skills/schema (`AGENTS.md` ↔ `CLAUDE.md`). 5. **Provider = config:** `agent: claude|codex`, one prompt/skills/schema (`AGENTS.md` ↔ `CLAUDE.md`).
6. Вход — **untrusted** (стектрейсы, bug-тексты, комментарии PR): передаём как данные, `--allowedTools` минимальный, никаких write-MCP. 6. Input is **untrusted** (stack traces, bug texts, PR comments): pass it as data, minimal `--allowedTools`, no write MCPs.
7. Всё идемпотентно: один fingerprint = одна ветка/PR; повтор не плодит дубли. 7. Everything is idempotent: one fingerprint = one branch/PR; a retry does not create duplicates.
--- ---
## 4. Варианты исполнения (venue) ## 4. Execution options (venue)
| | Описание | Плюсы | Минусы / риски | Когда | | | Description | Pros | Cons / risks | When |
|---|---|---|---|---| |---|---|---|---|---|
| **A. GHA + Bitrise Build Hub + `claude -p` / action (рекомендуемый старт)** | Workflow в apple-browsers: `dispatch/schedule` → Linux job (intake) → macOS job на Bitrise-label с агентом. | Уже используем для CI; ничего нового не покупаем; эфемерность; артефакты и OIDC из коробки; PR-цикл как у людей; тот же Xcode, что CI (ключевое для воспроизводимости). | Атомарно (без чата) → context-transfer ZIP; 360-мин лимит; нет внутренней сети (ok — данные приходят артефактом); egress на runner не контролируем → in-VM sandbox (Seatbelt) и prompt-hardening; ⚠️ claude-action на macOS не документирован → spike. | Фазы 1–3. Классы 1, 2, 3. | | **A. GHA + Bitrise Build Hub + `claude -p` / action (recommended start)** | A workflow in apple-browsers: `dispatch/schedule` → Linux job (intake) → macOS job on a Bitrise label with the agent. | Already used for CI; nothing new to buy; ephemeral; artifacts and OIDC out of the box; same PR loop as humans; same Xcode as CI (key for reproducibility). | Atomic (no chat) → context-transfer ZIP; 360-min cap; no internal network (fine, data arrives as an artifact); runner egress is not controlled → in-VM sandbox (Seatbelt) and prompt hardening; ⚠️ claude-action on macOS is not documented → spike. | Phases 1–3. Classes 1, 2, 3. |
| **B. Self-hosted Tart-раннеры (Virfield как база образов)** | Свои Mac mini + Tart + (Orchard/Tartelet/Cilicon) как GHA runner, образ с Xcode 26.4 из нашего image pipeline. | Полный контроль сети (egress allowlist → можно и внутренние данные); интерактивный доступ по SSH-туннелю; нет per-minute. | Нужно железо DDG (проект «Provision Mac» on hold; AWS EC2 Mac — дорого, 24ч минимум аренды dedicated host ⚠️); ops-нагрузка; Virfield не принят и сейчас = личный Mac с 2 VM (bus factor 1). | Фаза 4+, если A упрётся в стоимость/сеть. Virfield остаётся **dev/acceptance песочницей**. | | **B. Self-hosted Tart runners (Virfield as the image base)** | Our own Mac minis + Tart + (Orchard/Tartelet/Cilicon) as GHA runners, an image with Xcode 26.4 from our image pipeline. | Full network control (egress allowlist → internal data possible); interactive access over an SSH tunnel; no per-minute cost. | Needs DDG hardware (the "Provision Mac" project is on hold; AWS EC2 Mac is expensive, with a 24 h dedicated-host minimum ⚠️); ops load; Virfield is not accepted and is currently a personal Mac with 2 VMs (bus factor 1). | Phase 4+, if A hits cost/network limits. Virfield stays a **dev/acceptance sandbox**. |
| **C. Claude self-hosted environment на Mac (Tart VM на сессию)** | Runner Anthropic на macOS-хосте; триггеры: routines `POST /fire` (из Sentry/GHA), claude.ai/code. | **Resumable интерактив** с любого устройства (закрывает главный минус A); routines/API-триггер; ephemeral runner = чистый диск. | Beta, Team/Enterprise, ⚠️ macOS не подтверждён; owner-lock → нужен сервисный аккаунт; privacy/security triage Claude self-hosted уже «revisit»; зависимость от Anthropic control plane. | Фаза 4, после ответа Anthropic. Интерактивный «человек подключается». | | **C. Claude self-hosted environment on Mac (Tart VM per session)** | An Anthropic runner on a macOS host; triggers: routines `POST /fire` (from Sentry/GHA), claude.ai/code. | **Resumable interactive sessions** from any device (closes A's main gap); routines/API trigger; ephemeral runner = clean disk. | Beta, Team/Enterprise, ⚠️ macOS unconfirmed; owner lock → needs a service account; privacy/security triage for Claude self-hosted is already marked "revisit"; depends on the Anthropic control plane. | Phase 4, after Anthropic answers. Interactive "human joins". |
| **D. Bitrise RDE + Claude** | Долгоживущая macOS-VM с SSH/VNC и MCP. | Интерактив, suspend/resume, скриншоты/VNC. | Trial 1 сессия, баг private repos, нет внутренней сети, SSH-agent forwarding (обнулить), не масштабируется, оркестратор = локальный Claude. | Разовые сложные баги / UI-репро, не конвейер. | | **D. Bitrise RDE + Claude** | A long-lived macOS VM with SSH/VNC and MCP. | Interactive, suspend/resume, screenshots/VNC. | Trial = 1 session, private-repo bug, no internal network, SSH agent forwarding (blank it), does not scale, orchestrator = local Claude. | One-off hard bugs / UI repro, not a pipeline. |
| **E. Облачные Linux-агенты + CI как оракул** | Claude auto-fix PR / Seer hand-off / Codex cloud правят код без сборки; Bitrise CI валидирует. | Ноль инфраструктуры; быстро стартовать; хорош для lint/compile/очевидных тестов. | Не воспроизводят и не отлаживают flaky (нет Xcode); каждая итерация = полный CI-цикл (дорого/долго); авто-fix реагирует на CI, но не заменяет репродьюсер. | **Дополнение** к A: (1) Seer RCA как вход, (2) auto-fix на уже открытых AI-PR. | | **E. Cloud Linux agents + CI as the oracle** | Claude auto-fix PR / Seer hand-off / Codex cloud edit code without building; Bitrise CI validates. | Zero infrastructure; quick to start; good for lint/compile/obvious tests. | Cannot reproduce or debug flaky tests (no Xcode); every iteration is a full CI cycle (slow/expensive); auto-fix reacts to CI but does not replace a reproducer. | **Complement** to A: (1) Seer RCA as input, (2) auto-fix on already-open AI PRs. |
| **F. Bitrise AI Build Fixer** | Готовая фича Bitrise. | Ничего не писать. | ⚠️ Только build failures и, вероятно, только Bitrise CI; Pro/Enterprise; закрытая логика/валидация. | Не основа. Проверить, если есть частые build-поломки. | | **F. Bitrise AI Build Fixer** | A ready-made Bitrise feature. | Nothing to write. | ⚠️ Build failures only and probably Bitrise CI only; Pro/Enterprise; closed logic/validation. | Not a base. Check it if build breakages are frequent. |
**Рекомендация:** **A как основа + E как дополнение (Seer RCA / auto-fix)**, затем по данным выбрать **C или B** для интерактива и снижения стоимости. Virfield — для разработки/приёмки образов и промптов локально, чтобы не жечь Bitrise-минуты на отладку. **Recommendation:** **A as the base + E as a complement (Seer RCA / auto-fix)**, then choose **C or B** for interactivity and cost reduction based on data. Virfield is for developing/accepting images and prompts locally, so we don't burn Bitrise minutes on debugging.
### Claude vs Codex ### Claude vs Codex
- Один harness, два backend'а: `scripts/ai-fix/run-agent.sh --agent claude|codex`. Одинаковые вход/выход (`signal.json` → `summary.json` + ветка). - One harness, two backends: `scripts/ai-fix/run-agent.sh --agent claude|codex`. Same input/output (`signal.json` → `summary.json` + branch).
- Claude — первым (корпоративные ключи/плагины, `ddg-required-config`, OIDC federation, наши skills). Codex — как A/B-сравнение на одном eval-наборе и страховка от смены провайдера. Codex-action поддерживает macOS runner и `drop-sudo`; Codex cloud (Linux-контейнер) для Xcode не подходит ⚠️ (документация о macOS молчит). - Claude first (corporate keys/plugins, `ddg-required-config`, OIDC federation, our skills). Codex as an A/B comparison on the same eval set and insurance against a provider change. The Codex action supports a macOS runner and `drop-sudo`; Codex cloud (a Linux container) is not suitable for Xcode ⚠️ (the docs are silent about macOS).
- Сравнивать по метрикам §8 на одинаковых задачах, не «по ощущениям». - Compare by the §8 metrics on identical tasks, not by feel.
--- ---
## 5. Валидация (ядро плана) ## 5. Validation (the core of the plan)
### 5.1 Лестница по типу сигнала ### 5.1 Ladder by signal type
| Тип | Репро | Фикс считается валидным, если | | Type | Repro | A fix counts as valid if |
|---|---|---| |---|---|---|
| Flaky unit/integration | `-test-iterations N` / `-run-tests-until-failure` на том же Xcode/OS, **display awake** (иначе ложные dealloc-флаки, см. 10/14). Старт — данные из CI history (rate падений). | Красный до (≥K из N), зелёный **M/M** после (M≥15–20); не маскируется (`async`); весь класс + соседи зелёные; mocks сети/настроек; `swiftlint --strict` 0; собираются схемы `macOS Browser` и `macOS Browser App Store`. | | Flaky unit/integration | `-test-iterations N` / `-run-tests-until-failure` on the same Xcode/OS, **display awake** (otherwise false dealloc flakes, see 10/14). Start from CI history (failure rate). | Red before (≥K of N), green **M/M** after (M ≥ 15–20); not masked (`async`); whole class + neighbours green; network/settings mocked; `swiftlint --strict` 0; schemes `macOS Browser` and `macOS Browser App Store` build. |
| Failing test на main | bisect по last-green CI sha | Причина — тест или продукт? Если продукт — фикс + тест; после — unit полностью. | | Failing test on main | bisect against the last-green CI sha | Is the cause the test or the product? If the product — fix + test; afterwards the full unit suite. |
| Failing UI test | запуск `single_test_class` на notarized Review build через существующий workflow | Зелёный на target OS; потом по запросу matrix 14/15/26; `-retry-tests-on-failure` не считается за «зелёный». | | Failing UI test | run `single_test_class` on the notarized Review build through the existing workflow | Green on the target OS; then the 14/15/26 matrix on request; `-retry-tests-on-failure` does not count as "green". |
| Crash (Sentry) | **обязательный репродьюсер** (unit/UI/stress-тест). Нет репродьюсера → только RCA + гипотеза, без PR. | Тест красный до фикса и зелёный после; симптом из stack trace совпадает; нет новых крашей в соседних тестах. | | Crash (Sentry) | **a mandatory reproducer** (unit/UI/stress test). No reproducer → RCA + hypothesis only, no PR. | The test is red before the fix and green after; the symptom matches the stack trace; no new crashes in neighbouring tests. |
| Bug (Asana) | journey-скрипт, написанный агентом | Один и тот же скрипт, запущенный на base и на fix, показывает разницу; acceptance criteria из тикета; человек подтверждает направление до PR (двухшаговый режим). | | Bug (Asana) | a journey script written by the agent | The same script run on base and on fix shows a difference; acceptance criteria from the ticket; a human confirms the direction before the PR (two-step mode). |
### 5.2 Обязательный evidence bundle ### 5.2 Mandatory evidence bundle
`summary.json` по схеме: `signal_id`, `classification`, `root_cause`, `confidence`, `repro: {command, before: k/n fail, after: m/n pass}`, `validation: {schemes, lint, test_classes}`, `files_changed`, `outcome: fix | guard_tests_only | not_reproduced | needs_human`, `risks`, `commands_run`, плюс `.xcresult`/логи. PR-описание генерируется детерминированно из этого файла. `summary.json` by schema: `signal_id`, `classification`, `root_cause`, `confidence`, `repro: {command, before: k/n fail, after: m/n pass}`, `validation: {schemes, lint, test_classes}`, `files_changed`, `outcome: fix | guard_tests_only | not_reproduced | needs_human`, `risks`, `commands_run`, plus `.xcresult`/logs. The PR description is generated deterministically from this file.
### 5.3 Защита от «агент врёт» ### 5.3 Protection against "the agent lies"
- Валидацию выполняет **скрипт**, а не LLM: агент даёт команду/тест, harness сам гоняет N раз и сам считает. - Validation is done by a **script**, not by the LLM: the agent supplies a command/test, the harness runs it N times and counts itself.
- Приём Artur'а: **единый journey-скрипт для base и fix**. - Artur's trick: **a single journey script for base and fix**.
- Мутационная проверка (как 10/14): намеренно вернуть баг → тест обязан упасть. - Mutation check (as on 10/14): deliberately reintroduce the bug → the test must fail.
- Второй агент в чистом контексте — reviewer по `REVIEW.md` (`/code-review`), результат — комментарий в PR, не блокер. - A second agent in a clean context as reviewer per `REVIEW.md` (`/code-review`); the result is a PR comment, not a blocker.
- **Ограничение диффа:** лимит файлов/строк; изменение тестовой инфраструктуры/assertions без причины → `needs_human`; запрет ослаблять assertions и удалять тесты (как в skill `macos-uitest`). - **Diff limits:** file/line caps; changes to test infrastructure/assertions without reason → `needs_human`; weakening assertions and deleting tests are forbidden (as in the `macos-uitest` skill).
### 5.4 Eval-набор до включения автоматики ### 5.4 Eval set before enabling automation
Золотые кейсы (известный «правильный» фикс): AddressBarTests flake (корень в 2 местах), Ask AI Chat button animation leak, DeallocationTests display-sleep crash, Fire Window leak (**ожидаемый исход = not_reproduced**), плюс 5–10 исторических фиксов из `git log`/Asana «Apple CI Failing Tests». Метрики: найден ли корень, валиден ли фикс, **не придуман ли фикс там, где его нет**. Порог включения расписания — оговорённый заранее. Golden cases (known "correct" fix): the AddressBarTests flake (root cause in 2 places), the Ask AI Chat button animation leak, the DeallocationTests display-sleep crash, the Fire Window leak (**expected outcome = not_reproduced**), plus 5–10 historical fixes from `git log` / the Asana "Apple CI Failing Tests" project. Metrics: was the root cause found, is the fix valid, **was a fix not invented where none exists**. The threshold for enabling the schedule is agreed in advance.
--- ---
## 6. Безопасность и приватность ## 6. Security and privacy
Угрозы и меры: Threats and mitigations:
- **Prompt injection** через Sentry/Asana/PR-комментарии → входы как данные; минимальный `--allowedTools`; нет write-MCP; бюджет `--max-turns`; запрет сети кроме allowlist. - **Prompt injection** via Sentry/Asana/PR comments → inputs as data; minimal `--allowedTools`; no write MCPs; `--max-turns` budget; network denied except the allowlist.
- **Exfiltration:** агент без секретов приложения; GitHub App-токен узкий (`ai/*`); OIDC вместо статических ключей; **внутренние данные только в `signal.json` после scrub** (user data, URLs, PII) в доверенном Linux job; для Windows-версии уже открыт privacy follow-up по передаче blob → завести аналогичный triage для Apple. - **Exfiltration:** the agent has no application secrets; the GitHub App token is narrow (`ai/*`); OIDC instead of static keys; **internal data only in `signal.json` after scrubbing** (user data, URLs, PII) in a trusted Linux job; for the Windows version a privacy follow-up on blob transfer is already open, so open a similar triage for Apple.
- **Egress на Bitrise-раннерах** не контролируем → in-VM **Seatbelt sandbox** (Claude Code / Codex на macOS) + proxy allowlist (github.com, api.anthropic.com/api.openai.com, нужные registry/CDN); в варианте B — pf на хосте. - **Egress on Bitrise runners** is not controlled → in-VM **Seatbelt sandbox** (Claude Code / Codex on macOS) + proxy allowlist (github.com, api.anthropic.com / api.openai.com, required registries/CDNs); in option B — pf on the host.
- **SSH forwarding** (из triage): не пробрасывать `SSH_AUTH_SOCK`; в RDE-варианте — как в AT2/AT3. - **SSH forwarding** (from the triage): do not forward `SSH_AUTH_SOCK`; in the RDE option — per AT2/AT3.
- **Подпись:** build-with-secrets и agent — разные jobs; UI-тесты на ветке `ai/*` идут тем же путём, что человеческий PR (ruleset + environment approvals для secrets). - **Signing:** build-with-secrets and agent are separate jobs; UI tests on an `ai/*` branch go the same way as a human PR (ruleset + environment approvals for secrets).
- **Kill switch:** `vars.AI_FIX_ENABLED`, дневной бюджет $, `maxActiveRuns`, allowlist классов/путей (по умолчанию не трогаем: подписи, entitlements, `Package.swift` внешних зависимостей, релизные workflows, `.github/**`). - **Kill switch:** `vars.AI_FIX_ENABLED`, a daily $ budget, `maxActiveRuns`, an allowlist of classes/paths (by default do not touch: signing, entitlements, `Package.swift` of external dependencies, release workflows, `.github/**`).
- **Аудит:** transcript + commands в артефакт 30 дней (по аналогии с Virfield journal). - **Audit:** transcript + commands kept as an artifact for 30 days (like the Virfield journal).
- Review-гейты: privacy-triage на изменение (если PR трогает pixels/privacy — Danger/`privacy-review.yml` уже есть); PR template требует Asana-ссылку → **задачу Asana создаёт/привязывает человек или детерминированный сервис**, не агент. - Review gates: privacy triage for changes (if a PR touches pixels/privacy — Danger/`privacy-review.yml` already exist); the PR template requires an Asana link → **the Asana task is created/linked by a human or a deterministic service**, not by the agent.
- Не повторять: автономный LLM-оркестратор; запись в Asana/Discord из агента; прокси подписочных OAuth-токенов. - Do not repeat: an autonomous LLM orchestrator; writes to Asana/Discord from the agent; proxying subscription OAuth tokens.
Нужные согласования (параллельно с Phase 0): privacy triage + security triage на (а) Bitrise-runner + Anthropic/OpenAI API с кодом apple-browsers, (б) передачу scrubbed Sentry-данных, (в) Claude self-hosted (если C). Approvals needed (in parallel with Phase 0): privacy + security triage for (a) a Bitrise runner + Anthropic/OpenAI API with apple-browsers code, (b) passing scrubbed Sentry data, (c) Claude self-hosted (if C).
--- ---
## 7. Поэтапный план ## 7. Phased plan
### Phase 0 — выравнивание (≈1 нед, 2–3 чел-дня) ### Phase 0 — alignment (≈1 week, 2–3 person-days)
- Прийти в «AI Agent Infrastructure» ([проект](https://app.asana.com/1/137249556945/project/1219113011535833)) и к Chris Clarke: зафиксировать, что apple-browsers = build-and-fix на macOS через GHA + Bitrise (то, о чём уже договорились в комментариях), а не новый стек. - Join "AI Agent Infrastructure" ([project](https://app.asana.com/1/137249556945/project/1219113011535833)) and talk to Chris Clarke: record that apple-browsers = build-and-fix on macOS via GHA + Bitrise (what the comments already agree on), not a new stack.
- Свести с Artur/Sebastien/Tim (flux/pstack, verification) и Bárdi (Prefect crash flow, Windows runner) — взять **их** harness/skills, не писать свой; наш вклад — macOS-специфика (Xcode, XCTest, display sleep, UITestCase). - Sync with Artur/Sebastien/Tim (flux/pstack, verification) and Bárdi (Prefect crash flow, Windows runner) — take **their** harness/skills instead of writing our own; our contribution is the macOS specifics (Xcode, XCTest, display sleep, UITestCase).
- Открыть privacy/security triage (§6). Заказать dedicated API key (форма из тикетов) или OIDC federation. - Open the privacy/security triage (§6). Order a dedicated API key (the form from the tickets) or OIDC federation.
- Baseline-метрики: доля retry в CI, топ-N flaky-тестов за 30 дней (из JUnit), открытые «Apple CI Failing Tests». - Baseline metrics: CI retry share, top-N flaky tests over 30 days (from JUnit), open "Apple CI Failing Tests".
- Результат: решение по venue A, список stakeholders, согласованные guardrails. - Result: a decision on venue A, a stakeholder list, agreed guardrails.
### Phase 1 — детерминированный каркас + report-only (≈2 нед, ~8 чел-дней) ### Phase 1 — deterministic skeleton + report-only (≈2 weeks, ~8 person-days)
- Workflow `ai_triage_macos.yml` (schedule + dispatch): собирает JUnit из последних main/ночных запусков (`process-test-results`, `gh api` — как `ddg-diagnose-ci-failure`), считает fail-rate, фингерпринты, дедуп, eligibility; публикует отчёт (Mattermost/job summary). **Без LLM-записи.** - Workflow `ai_triage_macos.yml` (schedule + dispatch): collects JUnit from recent main/nightly runs (`process-test-results`, `gh api` — like `ddg-diagnose-ci-failure`), computes failure rate, fingerprints, dedupe, eligibility; publishes a report (Mattermost/job summary). **No LLM writes.**
- Схемы `signal.json` / `summary.json`; `run-agent.sh` (claude|codex), allowlist путей, бюджет. - `signal.json` / `summary.json` schemas; `run-agent.sh` (claude|codex), path allowlist, budget.
- Eval-набор из §5.4 + harness локально на **Virfield** (дешёвая отладка промптов на образе Xcode 26.4; при необходимости собрать образ из `image_create`). - The §5.4 eval set + harness locally on **Virfield** (cheap prompt debugging on an Xcode 26.4 image; build the image with `image_create` if needed).
- Spike S1 (claude/codex CLI на Bitrise-раннере: установка, auth, Seatbelt, стоимость минуты на одном тесте). - Spike S1 (claude/codex CLI on a Bitrise runner: install, auth, Seatbelt, cost per minute on a single test).
- Exit: отчёт ежедневно; eval-harness прогоняется; S1 дал цифры времени/стоимости. - Exit: a daily report; the eval harness runs; S1 gave time/cost numbers.
### Phase 2 — агент для тестов: draft PR по запросу (≈3 нед, ~12 чел-дней) ### Phase 2 — test agent: draft PR on request (≈3 weeks, ~12 person-days)
- `ai_fix_test.yml` (`workflow_dispatch`: `test_id`, `agent`, `mode`): Linux intake → macOS agent job (analyze → repro N раз → fix → validate) → evidence bundle → draft PR `ai/fix/<fp>` с лейблом. - `ai_fix_test.yml` (`workflow_dispatch`: `test_id`, `agent`, `mode`): Linux intake → macOS agent job (analyze → repro N times → fix → validate) → evidence bundle → draft PR `ai/fix/<fp>` with a label.
- Человек запускает вручную (как `$auto` у Duck.ai). Дальше — существующий PR CI; UI-тесты — отдельный dispatch оркестратора. - A human triggers it manually (like `$auto` in Duck.ai). Then the existing PR CI; UI tests via a separate orchestrator dispatch.
- A/B Claude vs Codex на eval-наборе. - A/B Claude vs Codex on the eval set.
- Цикл PR-feedback: комментарий `@ai-fix` или повторный dispatch → тот же ветка + context-transfer ZIP; опционально Claude auto-fix для CI-падений на `ai/*` (вариант E). - PR-feedback loop: an `@ai-fix` comment or a repeat dispatch → same branch + context-transfer ZIP; optionally Claude auto-fix for CI failures on `ai/*` (option E).
- Exit: ≥ порога по eval (корень найден, нет ложных фиксов); 5 реальных PR прошли ревью; средняя стоимость фикса измерена. - Exit: ≥ the threshold on the eval (root cause found, no false fixes); 5 real PRs passed review; average cost per fix measured.
### Phase 3 — крэши: Sentry → proposal → draft PR (≈3 нед, ~12 чел-дней) ### Phase 3 — crashes: Sentry → proposal → draft PR (≈3 weeks, ~12 person-days)
- Pre-fetch в доверенном Linux job (Sentry MCP/API; репозитории `apple-ios`, `apple-macos`; фильтр `firstRelease`, `app_version`, события ≥N; переиспользовать логику `ddg-sentry-report`) → scrub → `signal.json`. - Pre-fetch in a trusted Linux job (Sentry MCP/API; projects `apple-ios`, `apple-macos`; filters `firstRelease`, `app_version`, events ≥ N; reuse the `ddg-sentry-report` logic) → scrub → `signal.json`.
- Параллельно **trial Seer** на `apple-macos` в режиме «Stop after Solution» (если approve privacy): использовать RCA как дополнительный вход/бенчмарк; сравнить с нашим агентом. - In parallel a **Seer trial** on `apple-macos` in "Stop after Solution" mode (if privacy approves): use the RCA as an extra input/benchmark; compare with our agent.
- Двухшаговый режим по умолчанию: proposal (root cause + репродьюсер-тест + направление) → комментарий владельцу → после «да» агент делает PR. После накопления доверия (как в Windows-кейсе) — авто draft PR для краш-классов с воспроизведённым тестом. - Two-step mode by default: proposal (root cause + reproducer test + direction) → comment to the owner → after a "yes" the agent makes the PR. After trust accumulates (as in the Windows case) — automatic draft PRs for crash classes with a reproduced test.
- Exit: ≥X краш-находок с репродьюсером; доля принятых владельцами направлений. - Exit: ≥ X crash findings with a reproducer; share of directions accepted by owners.
### Phase 4 — автоматизация и интерактив (≈4–6 нед, по результатам) ### Phase 4 — automation and interactivity (≈4–6 weeks, depending on results)
- Включить расписание (ночной запуск top-K eligible), лимиты/бюджет, дашборд метрик. - Enable the schedule (nightly top-K eligible), limits/budget, a metrics dashboard.
- Выбор интерактива по данным: **C** (если Anthropic подтвердит macOS), **B** (если стоимость Bitrise-минут/сеть упрутся), или оставить D для редких случаев. - Choose interactivity by data: **C** (if Anthropic confirms macOS), **B** (if Bitrise minutes cost/network become a problem), or keep D for rare cases.
- Багфиксы из Asana (класс 4) — только после доказанной надёжности на 1–3 и в связке с flux/pstack. - Asana bug fixes (class 4) only after proven reliability on 1–3 and together with flux/pstack.
- Решение о релизных ветках — отдельно. - A decision on release branches is separate.
Ориентировочно до Phase 3 включительно: ~**8–10 недель календарно, ~35–45 чел-дней** (оценка грубая; сильно зависит от triage и результатов S1). Rough estimate through Phase 3: ~**8–10 weeks elapsed, ~35–45 person-days** (rough; depends heavily on triage and the S1 results).
--- ---
## 8. Метрики и критерии остановки ## 8. Metrics and stop criteria
- **Acceptance rate:** доля AI-PR, вмёрдженных без существенной переделки. - **Acceptance rate:** share of AI PRs merged without major rework.
- **Precision:** доля фиксов, прошедших эксплуатацию без регрессии; доля `not_reproduced`, которые на самом деле были реальными (false negative). - **Precision:** share of fixes that survived production without regression; share of `not_reproduced` outcomes that were actually real (false negatives).
- **Cost per merged fix** (токены + Bitrise-минуты), **time-to-PR**, **reviewer-minutes per PR**. - **Cost per merged fix** (tokens + Bitrise minutes), **time-to-PR**, **reviewer-minutes per PR**.
- **Flaky rate / CI retry rate** в main до/после; для крэшей — CPMN/crash-free дельта по затронутым сигнатурам. - **Flaky rate / CI retry rate** on main before/after; for crashes — the CPMN/crash-free delta for affected signatures.
- Стоп-условия: acceptance < порога два цикла подряд; любой инцидент утечки; бюджет превышен → автоматический kill switch. - Stop conditions: acceptance below threshold two cycles in a row; any leak incident; budget exceeded → automatic kill switch.
--- ---
## 9. Риски ## 9. Risks
| Риск | Митигирование | | Risk | Mitigation |
|---|---| |---|---|
| Агент «чинит» симптом (ослабляет assertion, добавляет sleep/retry) | Запрет в prompt + diff-политика + harness сам считает N/N + мутационная проверка | | The agent fixes the symptom (weakens an assertion, adds a sleep/retry) | Prompt prohibition + diff policy + the harness counts N/N itself + mutation check |
| Ложные фиксы flaky (сломали тест, а не продукт) | Классификатор «test bug vs product bug» + review-агент + owner | | False flaky fixes (the test was broken, not the product) | "test bug vs product bug" classifier + review agent + owner |
| Display sleep/окружение даёт другое поведение, чем CI | Тот же образ/Xcode, `caffeinate`/display awake, сравнение с CI-историей | | Display sleep/environment behaves differently from CI | Same image/Xcode, `caffeinate`/display awake, compare with CI history |
| Xcode-расхождение (26.4 vs 27) | Образ строго по `.xcode-version`; Virfield-профиль 26.4 | | Xcode mismatch (26.4 vs 27) | Image strictly per `.xcode-version`; a 26.4 Virfield profile |
| Стоимость Bitrise-минут/токенов | Бюджеты, top-K, ночной режим, Claude-sonnet по умолчанию, кэш (Bitrise build cache action) | | Bitrise minutes/token cost | Budgets, top-K, nightly mode, a Sonnet-class model by default, caching (Bitrise build cache action) |
| Prompt injection через Sentry/Asana | Scrub + data-only + минимальные tools + sandbox | | Prompt injection via Sentry/Asana | Scrub + data-only + minimal tools + sandbox |
| Дублирование чужих усилий (flux/pstack/Prefect/Bug Squisher) | Phase 0, общий harness, наш вклад — macOS-слой | | Duplicating others' efforts (flux/pstack/Prefect/Bug Squisher) | Phase 0, a shared harness, our contribution is the macOS layer |
| Бесконтрольный рост PR'ов | Один fingerprint = один PR, лимит открытых AI-PR, stale-auto-close | | Uncontrolled PR growth | One fingerprint = one PR, a cap on open AI PRs, stale auto-close |
| Зависимость от личной инфраструктуры (Virfield на одном Mac) | Virfield не в production-пути | | Dependence on personal infrastructure (Virfield on one Mac) | Virfield is not on the production path |
| Beta-фичи Anthropic (self-hosted, routines `experimental` header) | Не ставим на критический путь до GA | | Anthropic beta features (self-hosted, routines `experimental` header) | Not on the critical path until GA |
--- ---
## 10. Открытые вопросы (нужны решения/данные) ## 10. Open questions (need decisions/data)
1. Подтвердить venue A: кто DRI по macOS в AI Agent Infrastructure и можно ли выделить runner-label Bitrise под agent-jobs. 1. Confirm venue A: who is the DRI for macOS in AI Agent Infrastructure, and can a Bitrise runner label be allocated for agent jobs.
2. ⚠️ S1: работает ли `claude -p`/claude-code-action на Bitrise macOS runner (auth, Seatbelt, сеть)? Сколько стоит минута/задача? 2. ⚠️ S1: do `claude -p` / claude-code-action work on a Bitrise macOS runner (auth, Seatbelt, network)? What does a minute/task cost?
3. ⚠️ Ответ Anthropic: macOS runner для self-hosted environments — сроки и поддержка. 3. ⚠️ Anthropic's answer: a macOS runner for self-hosted environments — timing and support.
4. Privacy/security: можно ли отправлять scrubbed Sentry-стектрейсы и код apple-browsers агенту на Bitrise-раннере (OpenAI — отдельное согласование). 4. Privacy/security: may scrubbed Sentry stack traces and apple-browsers code be sent to an agent on a Bitrise runner (OpenAI needs a separate approval).
5. Где живёт конвейер: apple-browsers (`.github/workflows`) vs отдельный репозиторий + общий flux-плагин. 5. Where the pipeline lives: apple-browsers (`.github/workflows`) vs a separate repo + a shared flux plugin.
6. Кто владеет Asana-привязкой PR (шаблон требует ссылку на Asana): детерминированный сервис или человек. 6. Who owns the Asana linking of the PR (the template requires an Asana link): a deterministic service or a human.
7. Android: уточнить, есть ли отдельный проект (не нашёлся) — возможно, паттерн можно просто переиспользовать. 7. Android: clarify whether a separate project exists (none found) — maybe the pattern can simply be reused.
8. Нужен ли пилотный режим «только iOS/macOS unit-flaky» перед крэшами (рекомендую да). 8. Whether to run a pilot with "iOS/macOS unit flaky only" before crashes (I recommend yes).
--- ---
## 11. Первые конкретные шаги (на эту неделю) ## 11. First concrete steps (this week)
1. Написать короткий комментарий/таск в AI Agent Infrastructure с этим планом и вопросами 1–3 (без дублирования проектов). 1. Write a short comment/task in AI Agent Infrastructure with this plan and questions 1–3 (without duplicating projects).
2. Собрать eval-набор (4–5 кейсов из 10/14 + 5 из истории) и описать «ожидаемый исход». 2. Assemble the eval set (4–5 cases from 10/14 + 5 from history) and describe the "expected outcome" for each.
3. Локально на Virfield (или на dev-Mac) прогнать `claude -p` по одному кейсу с harness'ом «N× до/после» — получить baseline качества и стоимости до любых CI-интеграций. 3. Locally on Virfield (or a dev Mac) run `claude -p` on one case with the "N× before/after" harness — get a baseline of quality and cost before any CI integration.
4. Сделать spike S1 на Bitrise runner в отдельной ветке (workflow_dispatch, один тест). 4. Do spike S1 on a Bitrise runner in a separate branch (workflow_dispatch, a single test).
5. Подготовить draft privacy/security triage для (а) и (б). 5. Prepare a draft privacy/security triage for (a) and (b).
Связанные: [[work/wiki/apple-browsers/ci-pipeline]], [[work/wiki/apple-browsers/vm-ui-testing]], [[personal/projects/virfield]], [[personal/projects/personal-os/executor-v2-redesign]], [[personal/projects/personal-os/executor-security-analysis]], [[personal/projects/personal-os/personal-os-failed-approaches]], [[work/projects/macos-tests-worktrees-2026-10-14]], [[Research/Isolation of Agent Execution - OS and Container Level]]. Related: [[work/wiki/apple-browsers/ci-pipeline]], [[work/wiki/apple-browsers/vm-ui-testing]], [[personal/projects/virfield]], [[personal/projects/personal-os/executor-v2-redesign]], [[personal/projects/personal-os/executor-security-analysis]], [[personal/projects/personal-os/personal-os-failed-approaches]], [[work/projects/macos-tests-worktrees-2026-10-14]], [[Research/Isolation of Agent Execution - OS and Container Level]].