English · 日本語
アーキテクチャとモジュール関係¶
どのモジュールが何を担当し、どこに依存するか。また 設計(
DESIGN.md)に あるが現状まだ配線されていない機能 を明示します。
関連: concepts · 各機能ページ(下のリンク)
全体像(データフロー)¶
シナリオ(AI または人手で作成)が共有の成果物です。run は、それをゲートとして AI なしで決定的にリプレイします。codegen と triage もシナリオを入力として使います。
Tier 1(AI、図では黄)はオーサリングと調査のみを担い、Tier 2(決定的、図では青)は機械アサーションのみで合否を決めます。
この決定的な中核全体はプラットフォーム非依存で、プラットフォーム固有の継ぎ目は orchestrator が駆動する backend(iOS は idb / XCUITest、Android は adb、web は playwright、… いずれも 1 つの Driver インターフェースの背後)だけです。新しいプラットフォームは新しい backend であって、コアの fork ではありません。
Mermaid ソース
flowchart TB
goal(["🗣️ 自然言語ゴール"])
hand(["✍️ 人手編集"])
scenario[["📄 シナリオ (YAML)"]]
subgraph tier1["Tier 1 · AI — 著者 / 失敗調査役"]
record["record / crawl<br/>探索 + オーサリング"]
agent["Claude エージェント<br/>+ システムアラートガード"]
record <--> agent
end
subgraph tier2["Tier 2 · 決定的 run — CI ゲートに AI なし"]
orch["Orchestrator<br/>observe → act → verify"]
driver["backend 非依存ドライバ API<br/>tap · type · swipe · wait · query · screenshot"]
idb["idb バックエンド<br/>📱 iOS Simulator (simctl)"]
xcuitest["XCUITest バックエンド<br/>📱 iOS (常駐 runner)"]
adb["adb バックエンド<br/>🤖 Android"]
pw["playwright バックエンド<br/>🌐 web ブラウザ"]
orch --> driver
driver --> idb
driver --> xcuitest
driver --> adb
driver --> pw
end
verdict{"合否<br/>機械アサーションのみ"}
report["📊 Reporter<br/>manifest.json · JUnit · CTRF · HTML"]
codegen["codegen<br/>→ XCUITest / Playwright / UI Automator"]
triage["triage<br/>原因 + 修正案 · 助言のみ"]
goal --> record
record ==> scenario
hand ==> scenario
scenario ==> orch
scenario -.-> codegen
orch --> verdict
orch --> report
verdict -->|失敗| triage
triage -.->|修正案| scenario
classDef ai fill:#fde68a,stroke:#d97706,color:#1f2937;
classDef det fill:#bfdbfe,stroke:#2563eb,color:#1f2937;
class tier1 ai
class tier2 det
下の依存レイヤ図は、同じシステムをデータフローではなくモジュール層として見たものです。
モジュール一覧と役割¶
bajutsu/ パッケージ(Python 3.13+、pydantic v2 / typer / anthropic / pyyaml / jinja2)。
| モジュール | 役割 | ページ |
|---|---|---|
drivers/base.py |
Driver Protocol + 共通型(Element/Selector/Point)+ セレクタ解決(決定性の核) |
selectors / drivers |
drivers/coordinate_tree.py |
CoordinateTreeDriver。座標系の 2 バックエンド(idb、adb)が継承する共有基底クラス。一時的空ツリーへのリトライ / 安定キーによる settle / _resolve / wait_for を提供(BE-0254) |
drivers |
drivers/fake.py |
インメモリの FakeDriver(実機不要テスト用) |
drivers |
drivers/idb.py |
idb バックエンド(iOS Simulator。ヘッドレス、座標 tap) | drivers |
drivers/xcuitest.py |
XCUITest バックエンド(iOS。安定度ラダーで idb より上位。実機上に常駐する runner が semantic tap、ネイティブ条件待ち、multi-touch を提供し、idb はそのヘッドレスなフォールバック。BE-0019) | drivers |
drivers/adb.py |
adb バックエンド(Android。uiautomator dump による frame 中心の座標 tap。idb に相当する第 2 プラットフォーム) |
drivers |
drivers/playwright.py |
Playwright web バックエンド(ブラウザ。第一段、決定的 run) | drivers |
scenario/ |
シナリオスキーマ(pydantic 厳格検証)+ YAML 読込 / 書出(パッケージ: models / load / expand / select / serialize) |
scenarios |
assertions/ |
機械アサーション評価(総関数。例外を投げない)(パッケージ: evaluate / network / visual / schema / _common、BE-0250) |
selectors |
orchestrator/ |
決定的 Tier 2 run ループ(act → wait → verify)(パッケージ: loop / waits / substitution / evidence_rules / actions) |
run-loop |
evidence/ |
証跡の取得を役割ごとに分けたパッケージ(BE-0257):core(瞬時 / 区間の取得と Sink)、intervals(video / deviceLog の simctl 子プロセス管理)、network(collector + プロトコル内の決定的モック)、visual(ビジュアルリグレッションの画像比較)、golden(要素ツリー比較)、redaction(ラベル / ヘッダ / フィールド + シークレット値の redaction) |
evidence |
report/ |
manifest.json + JUnit XML + CTRF JSON + インタラクティブ HTML(パッケージ: format / manifest / ctrf / rows / panels / html) |
reporting |
interp.py |
${ns.key} 補間プリミティブ(params. / row. / secrets. / vars.) |
scenarios |
config/ |
チーム既定 × アプリ別の解決(Effective)(パッケージ: schema / effective / resolve / accessors) |
configuration |
backends.py |
バックエンド可用性判定、actuator 選択(プラットフォーム対応レジストリ: ios / android / web / fake)、Driver 生成 |
drivers |
simctl.py |
simctl ラッパ(erase/boot/launch/openurl/io) |
drivers |
preflight.py |
バックエンド別の実行可能ゲート(iOS: 必須 CLI + 起動済みシミュレータ / web: Playwright とその Chromium ブラウザ) | configuration |
requirements.py |
単一の宣言的マッピング。backend / capability から pip extra + 外部ツールのプローブ + インストール方法へ(BE-0164)。preflight と provision が共有する |
— |
provision.py |
config 対応の環境インストーラ(BE-0164)。config の backend と AI プロバイダを解決し、必要な extra とツールだけを冪等に導入する(make install) |
— |
runner/ |
config + シナリオ → レポート。デバイスプール + launch 手順。device_provider の seam が、run のデバイスをどこから調達するかを解決する(現状はローカルへの pass-through、将来はクラウドのアダプタ)(パッケージ: pipeline / pool / launch / device_provider) |
run-loop |
doctor.py |
規約充足度スコア(id カバレッジ等) | configuration |
agents/ |
AI / オーサリングエージェントの periphery(BE-0257):protocols + factory(Observation/Proposal/Agent 抽象 + 唯一の SDK エージェントの構築)、claude(オーサリングエージェント)、claude_backed(共有基底、BE-0246)、claude_enrich、claude_triage、ai_config(プロバイダ/モデル/effort/言語の解決)、anthropic_client(SDK クライアント構築)、availability(資格情報欠如のメッセージ化)、enrich(enrichment ループ)、alerts(システムアラートガード) |
recording |
ai/ |
ベンダー中立な AI バックエンドのシーム(BE-0104)。AiBackend プロトコルと正規化した request/response 型(base)、プロバイダレジストリ(registry)、agents.anthropic_client の上に立つ Anthropic 参照アダプタ(anthropic)。Anthropic API、Amazon Bedrock、Anthropic CLI ant(BE-0163)を賄います |
configuration |
record.py |
record ループ(observe → 提案 → 実行 → 書き出し) | recording |
crawl/ |
自律的な幅優先クロール → スクリーンマップ:core エンジン + serialize、guide / tabs / report / repro / flows |
recording |
codegen/ |
シナリオ → ネイティブテスト生成: XCUITest(Swift)、Playwright(TypeScript)、UI Automator(Kotlin) | codegen |
trace.py |
保存済み run のテキストタイムライン(trace コマンド) |
cli |
triage.py |
M4 自己修復: ルールベース HeuristicTriageAgent + 構造化 fix(renameId/addIndex/raiseTimeout)、--apply/--write/--rerun |
cli |
github/ |
GitHub ヘルパ:actions(CI、アノテーション + ジョブサマリ)、app(プライベートリポジトリの config source 向けの App インストールトークン)、errors(共有するアクセスエラー) |
ci |
serve/ |
ローカル Web UI(serve コマンド): オーサリング / 実行 / レポート / 失敗した run の triage |
cli |
mcp/ |
MCP サーバ: run/doctor をツール + 実行証跡をリソースとして公開 |
cli |
lint.py |
シナリオ linter + JSON Schema 生成(lint / schema コマンド) |
cli |
analysis/ · serve/flakiness.py |
実機も AI も使わない読み取り専用の助言的分析パッケージ(BE-0257)、CI を止めない: audit(決定性・フレーキネス監査、BE-0049)、coverage(シナリオの id 名前空間カバレッジ、BE-0050)、stats(集計 run 統計ダッシュボード、BE-0102)、加えてクロスランのフレーキネスランキング(flakiness、BE-0220) |
cli |
cli/ |
Typer ベース CLI。コマンドごとに cli/commands/ の 1 ファイル(run/project/doctor/audit/coverage/stats/flakiness/export/trace/report/triage/record/crawl/codegen/approve/serve/mcp/worker/lint/schema) |
cli |
dotenv.py |
.env の最小ローダ(既存環境変数を上書きしない) |
cli |
_yaml.py |
on/off/yes/no を文字列のまま読む YAML ローダ |
scenarios |
依存関係(レイヤ)¶
下層ほど安定で、上層が下層に依存します。中核は drivers/base.py(セレクタ解決)で、すべての実行系がここに依存します。
Mermaid ソース
flowchart TB
cli["cli/<br/>ユーザ接点(Typer): run · project · doctor · audit · coverage · stats ·<br/>flakiness · export · trace · report · triage · record · crawl · codegen ·<br/>approve · serve · mcp · worker · lint · schema"]
runner["runner/"]
record["record.py / crawl/<br/>(Tier 1 / AI)"]
codegen["codegen/<br/>(構造マッピング)"]
trace["trace.py<br/>(タイムライン)"]
triage["triage.py / agents/claude_triage.py<br/>(自己修復・助言)"]
orch["orchestrator/"]
agentStuff["agents/<br/>(protocols・factory・claude・alerts 等)"]
serveGh["serve/ · github/<br/>(Web UI・CI)"]
assertions["assertions/"]
evidence["evidence/<br/>(core + intervals・network・visual・golden・redaction)"]
scenario["scenario/<br/>(interp.py)"]
report["report/"]
config["config/ · preflight.py"]
backends["backends.py"]
simctl["simctl.py"]
base["drivers/base.py<br/>決定性の核(Element / Selector / resolve_unique)"]
fake["drivers/fake"]
ios["drivers/idb・xcuitest・adb"]
pw["drivers/playwright"]
cli --> runner
cli --> record
cli --> codegen
cli --> trace
cli --> triage
runner --> orch
record --> agentStuff
triage --> serveGh
orch --> assertions
orch --> evidence
agentStuff --> assertions
assertions --> scenario
evidence --> report
orch --> config
orch --> backends
orch --> simctl
scenario --> base
report --> base
config --> base
backends --> base
simctl --> base
base --> fake
base --> ios
base --> pw
orchestrator/はbase.Driverにのみ依存し、どの具象ドライバとも結合しません。そのためFakeDriverで実機なしにテストでき、本番では同じループが idb(iOS)や playwright(web)を駆動します。runner/はアプリを起動して準備済みドライバを返す factory を提供し、ループを実機から分離します。scenario/(オーサリング表現の pydantic モデル)とdrivers/base.py(実行時の TypedDict)は別物です。Selector.as_selector()が前者を後者へ変換します。
強制されるレイヤ境界(BE-0112)¶
上のレイヤ分けは規約にとどまりません。ゲートで実行可能な契約として強制します。make lint-imports(make check の一部であり、CI のステップでもあります)が import-linter を宣言したレイヤに対して実行するので、禁止された import は誰かが気付くまで残らず、その場でゲートを落とします。設定は pyproject.toml の [tool.importlinter] にあります。3 つのレイヤを宣言します。
- 決定性コア:モデルにも periphery のスタックにも触れずに判定と証跡を導く経路です。
orchestrator/、runner/、drivers/base.py、assertions/、evidence/、report/、config/、scenario/、preflight.py/capability_preflight.py/capabilities.py、doctor.py、lint.pyが含まれます。prime directive を担います。 - 契約(contract):利用者が依存する安定した界面です。シナリオスキーマ(
scenario/)とDriverProtocol(drivers/base.py)です。 - periphery:契約の利用側で、いずれもオプションの extra の背後に切り離せます。
serve/、mcp/、codegen のエミッタ、AI / エージェント経路(agents/以下のprotocols、ai_config、anthropic_client、enrich、alertsなど、加えてrecord.py、triage.py、crawl/guide.pyなど)、github/actions.py/notify.pyのヘルパです(github/の残り、appとerrorsは決定的コアからも参照できるので、config_sourceは periphery を巻き込まずに利用します)。
強制する契約は 3 つです。
- 決定性コアは periphery を import してはいけません。 これはprime directive 1 と 3 を静的な契約にしたものです。判定と証跡の経路を serve / AI / codegen のスタックから切り離したまま保ち、それらへの依存が黙って増えることを防ぎます。コアのモジュールが必要とする純粋な要素ツリーのヘルパ(
screen_size_from_elements、shows_app_uiなど)は、record.pyのような periphery のモジュールではなくコア(bajutsu/elements.py)に置きます。同様に、解決済みのaiブロック(AiConfig)はconfig/に置き、コアは AI クライアントを import せずにそれを読みます。 - コアはホスト非依存に保ちます(BE-0129)。 マルチテナントなホスティングの関心事(組織、ロール、テナンシー)と、
db(SQLAlchemy、Alembic、psycopg、cryptography)やoauth(Authlib)の extra は、bajutsu/serve/だけが持ちます。組織モデル(OrgConfig、org_for_*、targets_for_org、load_serve_config)はconfig/ではなくbajutsu/serve/orgs.pyにあります。Configはorgsフィールドを持たず、コアのローダーは検証の前にトップレベルのorgs:を取り除くので、組織情報を含む config を読むホスト型構成の run はそのまま動きつつ、コアは組織を一切モデル化しません。同じ仕組みがトップレベルのui:キー(BE-0191)も除去します。serve UI のプレゼンテーション設定(ui.default_theme)は serve の関心事であり、bajutsu/serve/themes.pyで読み取られます。Configはモデル化しません。import-linter の forbidden 契約がconfig/・drivers/・runner/・scenario/をこれらの extra から遠ざけます(include_external_packagesにより外部 import も検出します)。これは、それらをbajutsu.serveから遠ざける periphery 契約の上に重ねたものです。 - シナリオスキーマと
DriverProtocol は可搬なインナー契約に保ちます。 periphery だけでなく runtime のコア(orchestrator/、runner/、config/など)からも独立させます。これにより契約は、利用者が runtime を引き込まずに依存できる安定したレイヤになり、バージョンをまたいだスキーマの読み取り(BE-0119)や、将来 periphery をコアから分離する余地を下支えします。
このチェックは import グラフに対する静的解析です。モデルは介在せず、決定的な合否以上のものは run / CI の判定経路に載りません。新しいモジュールを追加するときは、そのレイヤが置き場所を決めます。判定と証跡の経路上にあるならコアであり、periphery に到達してはいけません。契約を利用するなら periphery であり、extra の背後に置きます。
テスト構成¶
tests/ に ユニットテスト一式(uv run pytest -q)があります。すべて実機 Simulator を必要としません。コマンドビルダは純関数として、実行系は FakeDriver / 注入ランナー(RunFn、Spawn、Clock)で検証します。showcase アプリに対する実機 E2E は make -C demos/showcase run-swiftui / make -C demos/showcase ui-test です(showcase)。
driver conformance suite(BE-0114)¶
prime directive 3 は、どの backend も 1 つの Driver 界面の背後に置くことを求めます。ですから決定性の中核となる不変条件は、すべての backend で同一に成り立たなければなりません。backend ごとのテストだけでは、これを保証できません。曖昧なセレクタで最初の一致を tap する backend や、0 件の query に成功を返す backend があっても、自身のテストは通り、落とす共通テストがないからです。driver conformance suite はこの隙間を埋めます。1 つの実行可能な契約(technology compatibility kit(TCK)に相当します)が、同じテスト本体をすべての backend に対して走らせ、共通の base だけでなく実際のドライバのインスタンス(drivers/base を迂回するコードを含みます)を駆動します。
契約(tests/driver_conformance.py)は、新しい backend が満たすべき「完了」の定義です。
- 曖昧なセレクタ(2 件以上の一致)は、最初の一致に作用せず失敗します。
- 0 件のセレクタは、成功を報告せず失敗します。
- セレクタの失敗は 1 つのエラー型(
SelectorError)を共有し、backend をまたいで一様です。 - 一意の一致はエラーなく作用し、
query()は画面上の要素を報告します。 capabilities()が観測される挙動と一致します。QUERY/ELEMENTSの baseline を申告し、multi-touch のジェスチャはMULTI_TOUCHを申告したときに限り、全選択とクリップボードへのコピーはTEXT_SELECTIONを申告したときに限り動作します(そうでなければそれぞれUnsupportedActionを送出します。BE-0280)。- フォーカス中のフィールドでテキスト編集が往復します(入力してから削除すると、報告される文字数が減ります)。また
tap_point(生の座標タップ。アラート消去の経路)は、フィールドの中心を狙うとそのフィールドをフォーカスし、semantic tap と同じ観測可能な効果を持ちます(BE-0280)。 wait_forは現在の画面を 1 回だけ判定し、共有のwait_untilループがそれを固定 sleep なしの条件待ちに変えます。
backend をこのスイートに加えるには、ConformanceHarness(画面を渡すと、それを表示するドライバを返すもの)を実装し、DriverConformanceContract を継承します。すると pytest が、継承した契約をその backend に対して走らせます。FakeDriver は高速な Linux ゲート(make check)で、Playwright は web CI ジョブで、idb と XCUITest は iOS のオンデバイス E2E 経路(ios-e2e.yml)で、adb backend は起動済みの Android エミュレータ(android-e2e.yml の conformance (adb) ジョブ、BE-0270)で走ります。契約は同じで、第 2 の仕様はありません。
各 harness は画面をそれぞれの方法で実体化します。FakeDriver は要素をそのまま受け取り、Playwright は HTML として描画します。オンデバイスの harness は SHOWCASE_CONFORMANCE で showcase アプリを一度だけ conformance モードで起動し、以降は画面ごとに再シードします。これにより、共有の base だけでなく、実際の backend の query と操作のコードを駆動します。
iOS の harness は、アプリがポーリングする spec ファイル(Documents ディレクトリの conformance-spec.txt)を書き換えて再シードします。画面ごとの再起動や deeplink ではなくファイル書き込みにするのは、simctl openurl が iOS の「アプリで開きますか?」ダイアログを出し、画面ごとの再起動は数回の app.launch() で常駐 XCUITest ランナーをクラッシュさせるためです。
adb の harness はその代わりに、新しい SHOWCASE_CONFORMANCE の intent extra を載せてアプリの singleTask Activity を起動し直し、onNewIntent で届けます。adb push はアプリのサンドボックスに届かず、インテントなら launchEnv→intent extras の規約(BE-0007)に乗るからです。これは Compose ツールキットに限定します。spec 駆動で任意の id を描く画面を表現できるのは Compose だけです(testTag は実行時の任意の文字列を受け取りますが、Views の resource-id はコンパイル時の R エントリでなければなりません)。
このスイートには ondevice の pytest マーカーが付いており(ゲートの既定で除外されます)、make check では決して走りません。共有する 1 台のデバイスを 1 つのチャネルで再シードするため、並列ワーカーどうしが衝突しないよう直列で実行します。
実装状況¶
設計(
DESIGN.md)には将来像も含まれます。現状のコードが実際に動かすものと まだ配線されていないものを区別します。
実装済み(テストあり、経路が通っている)¶
- セレクタ解決と曖昧検出(決定性の核)
- プラットフォーム対応の backend レジストリ:
--backend/backend:はios/android/web/fakeトークンを受け取り、それぞれの actuator へ展開します(backends.py)。iosはxcuitestとidbに展開します。actuator を複数持つプラットフォームはシナリオごとにコスト順で解決し(BE-0240)、各シナリオを、そのステップが使える最も安い actuator で走らせ、安いほうに無い能力を必要とするときだけ昇格します - XCUITest バックエンド(
drivers/xcuitest.py): より高機能な iOS actuator です。実機上に常駐する runner(BajutsuKit)を loopback HTTP 経由で駆動し、semantic(identifier)tap、ネイティブの条件待ち、idb が持たないpinch/rotateの multi-touch ジェスチャ(idb ではUnsupportedAction)を追加します。idb はシナリオごとの安い既定(Xcode ツールチェーンも常駐 runner も不要)で、シナリオが idb に無い能力を必要とするときだけ XCUITest へ昇格します(BE-0240)。明示的に--backend xcuitestを固定したホストでは XCUITest が唯一の actuator になります(BE-0019) - Playwright web バックエンド(
drivers/playwright.py): ブラウザに対する決定的runを Linux のゲート上で動かせます(demos/web)。リッチ寄りの能力モデルまで引き上げ済み(BE-0054):page.route()によるネイティブなnetworkの観測とスタブ、共有のdriver_intervalseam を通したvideoとdeviceLog相当(console / page-error)の区間証跡、multiTouch(ピンチ / 回転)のエミュレーション、N 個のBrowserContextレーンにまたがる並列実行、ターゲット単位のdeviceMode(既定はデスクトップで、Playwright のデバイスプリセットを指定するとモバイルをエミュレーションします。BE-0228)。appTraceのみ iOS 専用(os_log/simctl 由来)のまま - Android adb バックエンド(
drivers/adb.py+adb.py): 座標ドライバ(uiautomator dump→ frame 中心タップ)、AndroidEnvironmentの起動シーケンス、doctorの報告、interval 証跡(videoはscreenrecord、deviceLogはlogcat。どちらも driver 供給のdriver_intervalseam を通す)とアプリ内のネットワーク捕捉 — OkHttp インターセプタ(BajutsuAndroid)がホストのコレクタへ報告し、そのコレクタをadb reverseでエミュレータへ橋渡しするrequestアサーション(BE-0283。mocksは追随の課題)、取得済み XML フィクスチャに対する fast ゲートのユニットテストまで。実機上での actuation は idb と同等の水準に達しており、システムback、deeplink、単一ラウンドトリップのdoubleTap、スクロールによる要素解決、実行時パーミッションの事前付与を含みます(BE-0210)。デバイス制御はsetLocationとクリップボードの読み書き / クリアの部分集合を、操作ごとの capability トークンで管理する形で実装済みです(BE-0211 / BE-0212)。クリップボードは Android 10 以降シェルプロセスから到達できないため、アプリ内のレシーバ(BajutsuAndroid、BE-0233)を経由します。一方、push/clearKeychain/ ステータスバーの上書き /background/foregroundは、エミュレータ側に相当機能がないため未対応のまま残ります。シナリオ単位のpermissionsフィールド(pm grant/pm revoke、BE-0276)は権限の語彙全体(API 33 以降のPOST_NOTIFICATIONSを含むnotificationsも)に対応しており、対応する TCC(Transparency, Consent, and Control)サービスを持たない iOS のsimctl privacyとは異なります。pinch/rotateの 2 本指マルチタッチは rooted device 限定で実装済み(protocol-B のsendevent、単一タッチへのフォールバックなし。BE-0232)。codegen は UI Automator(Kotlin)ターゲットを実装済み(BE-0209)。Android の e2e CI レーン(KVM 上のエミュレータ、android-e2e.yml。BE-0208)は実装済みで、モックネットワーク系を除く共有シナリオ一式を実行します。adb ドライバは、iOS と同じ横断バックエンドのセレクタでネイティブのタブバーを操作し、あらゆるタブに到達できます(クリック可能なNavigationBarItemがbuttonトレイトを持ち、子要素のテキストをlabelとして派生させます。BE-0223)。タブバー操作の欠落こそが、タブに紐づくシナリオをレーンから除外していた唯一の移植性の課題でした。id の照合はドライバ内で厳密一致のままです。native な id 構文が SPEC の id を再現できない場合(Android Views のandroid:idはstable.refreshをstable_refreshに写します)は、シナリオのセレクタが id を両方の形で列挙し、共有リゾルバが OR としてどちらにも一致します。ドライバ側の.↔_書き換えではなく、シナリオ側の明示的な規約です(BE-0221) - シナリオスキーマ(厳格検証)と YAML ラウンドトリップ。
id/idMatchesはプラットフォーム別の id 形に対応する OR 候補のリストを受け付けます(BE-0221) - アサーション評価(
exists/value/label/count/enabled/disabled/selected/request/requestSequence/event/responseSchema/visual/clipboard/golden) - Tier 2 run ループ(act → wait → verify)、
FakeDriverで検証 - DSL(ドメイン固有言語):
withinセレクタ(幾何スコープ)、relaunchステップ(実機検証済み)、再利用setup前段、起動時のlocale適用、デバイスプール上の並列実行(--workers) - DSL のオーサリング再利用: 再利用可能なパラメータ化コンポーネント(
use/${params.*})、データ駆動シナリオ(data/dataFileと${row.*})、シークレット変数(${secrets.X}、値マスク)、シナリオタグ +--tag/--exclude選択、setLocation/pushデバイスステップ、起動前のpermissionsフィールド(simctl privacy/pm grant|pm revoke、BE-0276)、doubleTapアクション、ファイル単位 + シナリオ単位のdescription - DSL の制御フローとデータ取得: 条件分岐
ifとループforEach(決定的。条件は機械アサーション)、extract(要素の value / label / identifier を${vars.*}に取り込む) - DSL のテキスト編集ステップ(BE-0265):
clear/delete/select/copyがtypeだけでは埋まらない部分を補います。adb・Playwright・XCUITest・fake の各バックエンドに実装済みで、idb と web コンテキストはselect/copyでUnsupportedActionを送出し(codegen 側は代わりに XCUITest へ誘導)、web コンテキストはclear/deleteでも同様に非対応です。ステップをまたぐSelectionStateが「copyの前にselectが必要」という前提条件を担保し、どのバックエンドも選択状態を照会可能な形で公開しないため、検証は既存のclipboard読み戻しのみで行います - DSL のデバイス / システムアクション(iOS):
background、clearKeychain、clearClipboard、overrideStatusBar/clearStatusBar(決定的なステータスバー)、テストデータ準備 / Webhook 用のhttpアクション - 証跡: 瞬時(
screenshot/elements/actionLog)+ 区間(video/deviceLog/appTrace)+ ネットワーク collector(network.json)+ ビジュアルリグレッション(baseline に対するvisual。approveコマンドで baseline を昇格)+capturePolicy発火 + 書き出し前の redaction 適用 - ネットワーク観測 + 決定的モック(シナリオ
mocks→ プロトコル内スタブ、実機検証済み):requestアサーション、wait: { until: request }、オフラインのスタブ応答 - レポート(
manifest.json/junit.xml/ctrf.json/report.html) - config 解決(defaults × targets、redact マージ)と actuator 選択
simctlコマンド層、idb の出力パーサ、doctorスコア + バックエンド別の実行可能ゲート(preflight.py: iOS は必須 CLI + 起動済みシミュレータ、web は Playwright とその Chromium ブラウザ)traceコマンド(trace.py): 保存済み run のテキストタイムライン(steps + network + appTrace)- M4 自己修復トリアージ(
triage.py+agents/claude_triage.py): 失敗 run のコンテキスト組み立て +TriageAgent診断(ルールベースHeuristicTriageAgent、または--aiの Claude で失敗スクリーンショット込み)。エージェントは構造化 fix(renameId/addIndex/raiseTimeout)を提案でき、--apply/--writeでシナリオ source に適用(diff プレビュー、opt-in)、--rerunで再実行検証 - CLI:
run/project/doctor/audit/coverage/stats/flakiness/export/trace/report/triage/record/crawl/codegen/approve/serve/mcp/worker/lint/schema。recordとcrawlが Tier 1 の AI オーサリング経路で、alert guard を伴います - 実機も AI も使わない読み取り専用の助言的な分析コマンド(CI を止めない。入力が欠けている、読めないときだけ非ゼロで終了します): 静的、repeat-and-diff、longitudinal の 3 モードを持つ決定性・フレーキネス監査(
audit、BE-0049)、シナリオの id 名前空間カバレッジマップ(coverage、BE-0050)、CLI / HTML 出力の集計 run 統計ダッシュボード(stats、BE-0102)、runs ディレクトリまたはserveのデータベースから見るクロスランのフレーキネスランキング(flakiness、BE-0220)、完了した run を持ち運び可能な.zipにまとめる export(export、BE-0060)、保存済みの run データから再実行なしにreport.html/junit.xml/ctrf.jsonを再生成する report(report、BE-0068) - config プロジェクトハブ(
project add/ls/use/rmとrun --project、BE-0225): プロジェクト名を config のソースに束ねる名前付きレジストリで、CLI とserveの Web UI が共有します(データベースがあればそこに保存し、なければディスク上の JSON に保存します)。serveはヘッダーのプロジェクト切り替えと、プロジェクトを一覧・追加・削除・切り替えするトップレベルの Projects ページ(BE-0275)を備え、再起動なしにアクティブな config を切り替えます - クロスプロジェクトのメトリクス比較ダッシュボード(BE-0226):
serveの Metrics タブが、登録済みのプロジェクトを pass 率、flaky 率、p50/p95 の run 所要時間、そしてプロジェクトごとのトレンドスパークラインで横並びに順位付けします。BE-0102 のプロジェクト単位の集計をプロジェクトごとに 1 回ずつ実行して再利用します(GET /api/metrics/projects)。BE-0102 と同じく読み取り専用でアドバイザリ - AI crawl(
crawl/): アプリを自律的に幅優先で探索し、スクリーンマップ(screenmap.json)を作ります serveローカル Web UI(Tier 1): ブラウザからシナリオをオーサリング(record/crawl)、編集、実行し、config + シナリオ + ビルド済みアプリバイナリの.zipバンドルをアクティブな config として開いて各タブをそこから動かします(BE-0073)。サーバはこの 3 つをそれぞれ独立した content-addressed な成果物としても受け付け、バインド時にそのツリーへ合成します(POST /api/artifacts/{config,scenarios,binary}、BE-0268)。UI にもCompose & load パネルを備え、成果物ごとのドロップゾーンでブラウザ側でハッシュ化し、サーバがまだ持たないバイト列だけをアップロードしたうえで、要求に応じてバインド済みの config へ合成します。レポートと証跡を閲覧できます。集計 run 統計ダッシュボードの各軸(日付、backend、シナリオ、step/assertion のホットスポット)から履歴一覧の該当する run へ直接ジャンプできます(BE-0241)。Record と Replay のフォームでは実行前の準備状況パネル(doctor: 環境の runnability と現在画面の規約スコア)を確認でき(BE-0148)、Replay のフォームでは実行前に選択中のシナリオの生の YAML とランナー解析による構造化ステップを読み取り専用で表示します(config ビューアのシナリオ版で、実行の判定には関与せず AI も使いません。BE-0273)。プラグイン可能なテーマシステム(ドロップイン方式のビジュアルトークンと差し替え可能なトランジション、ヘッダーのピッカー、ライブプレビュー付きの UI 内エディタとローカル下書き / サーバアップロードの永続化。BE-0191)を備え、このページを配信している bajutsu 自身のビルドをヘッダーに示すバージョンバッジを持ちます(バージョン文字列は常に表示し、Git チェックアウトから起動しているときは短縮コミット SHA、ブランチ名、dirty 判定も添えます。.gitを持たないセルフホストの Docker イメージでは、ビルド時に埋め込んだコミット(BAJUTSU_BUILD_COMMIT。source: "build-arg"として示します)にフォールバックします。ブランチ名は作業中のトピックを含みうるため、チェックアウトの詳細は admin に制限します。GET /api/versionは公開、GET /api/version/checkoutは admin で、リクエストのたびにgitの plumbing コマンドで最新を読み取り(環境変数へのフォールバックつき)、LLM は介しません。BE-0272、BE-0277)。ビジュアル baseline を承認し、ジョブをライブ配信します(CI 用ではありません)- MCP サーバ(
bajutsu mcp):bajutsu_runとbajutsu_doctorを MCP ツールとして、実行証跡をリソースとして公開します。Claude Desktop / Code との連携用(オプション依存fastmcp) - シナリオ linter(
bajutsu lint/bajutsu schema): 実行せずにシナリオを検証します。エディタ連携用に JSON Schema も出力します - codegen: シナリオ → ネイティブテスト。共有のシナリオ走査(BE-0083)の上に、XCUITest(Swift、iOS)、 Playwright(TypeScript、web)、UI Automator(Kotlin、Android。BE-0209)の 3 ターゲット
実機 Simulator で検証済み(iPhone 17 Pro、近年の iOS)¶
- idb バックエンドの subprocess 実行(
describe-allパース、フレーム中心の tap / text / swipe、simctllaunch 手順)を、インストール済みのidb/idb_companionに対して確認しています。showcase シナリオの実行、証跡の取得、triage 自己修復ループを実機で走らせて検証しました(make -C demos/showcase run-swiftui。ios-e2e.ymlCI も idb smoke を実行します)。 - idb バックエンドの
backとデバイス制御(setLocation/ クリップボード /push)を実機上で実行しています。ios-e2e.ymlのactuation (idb)ジョブが PR ごとに検証します(BE-0281)。 - XCUITest バックエンドの常駐 runner を実機で検証しています。スナップショットハンドルによる要素解決、semantic tap、idb では動かせない
pinch/rotateの multi-touch ジェスチャを、ios-e2e.ymlのxcuitest (multi-touch)ジョブ(demos/showcase/scenarios/gestures_multitouch.yaml、--backend xcuitest)で確認済みです。
ブラウザで検証済み(Linux で動作、Mac 不要)¶
- Playwright web バックエンドは
demos/webのシナリオを、CI と同じmake checkゲートの中(ci.ymlのweb-e2eジョブ)で決定的に実行します。決定的コアがプラットフォーム非依存であることの裏付けです。リッチ寄りの web 取得(ネットワーク / 動画 / マルチタッチ)は BE-0054 で実装済みです。N 個のブラウザプロセスにまたがる並列 web クロール(BE-0077)は、この同じゲートの上で動きます。 - 実ネットワーク経路(
page.routeの介入、requestfinishedのキャプチャ、mockedの来歴フラグ、実際にキャプチャした証拠の redaction)は、ゲート対象外のnetwork (playwright)ジョブ(web-e2e.yml。BE-0282)が実ブラウザに対して動かします。このジョブはdemos/web/scenarios/network.yamlを network を有効にして 実行し、続いて永続化されたnetwork.jsonがキャプチャした秘密情報をマスクしていることをアサートします。まずシグナルとして着地させ、安定を確認してから必須に昇格させます。iOS 側(network_mock.yamlとnetwork_live.yamlを Simulator ジョブとしてつなぐ)はまだ未完です。Android は現在、アプリ側のネットワークキャプチャ(BE-0283)に対応しています。BajutsuAndroid の OkHttp インターセプタが、各リクエストをadb reverseトンネル経由でホストの collector へ報告する仕組みで、iOS でBajutsuKitが使うのと同じアプリ側連携の形です。adb ドライバ自体は、アクチュエーションの対象になるネイティブのネットワークモニタがないため、引き続きネイティブなNETWORKcapability を宣言しません。そのためnetwork (adb)ジョブ(android-e2e.yml)は、ドライバの capability を介さず、このアプリ側の経路を直接検証します。
Android エミュレータで検証済み(Linux で動作、Mac 不要)¶
- adb バックエンドの subprocess 実行(
uiautomator dumpパース、フレーム中心の tap、AndroidEnvironmentの起動シーケンス、idb と同等の actuation fidelity、pinch/rotateのマルチタッチとデバイス制御のスライスを含む)を、KVM 上で起動した x86_64 API 34 AVD に対して確認しています(android-e2e.yml、BE-0208)。idb が走らせるのと同じ共有シナリオを Compose と Views 両方の showcase ビルドで駆動し、Compose カタログの golden 要素ツリー検査とピクセル単位のビジュアルリグレッション baseline も併せて確認しています。このレーンは常駐 UI Automator サーバ(BE-0245)もビルドするので、これらの読み取りは既定で常駐チャネル(adb forward越しのGET /source。1 回約 2.4 秒のuiautomator dump起動を置き換えます)を通り、uiautomator dump経路はダンプへフォールバックさせた golden の実行で守ります。
未配線(スキーマ/フラグはあるが実行時に効かない)¶
| 機能 | 現状 | 場所 |
|---|---|---|
mockServer(外部モックコマンド) |
config スキーマのみ。cmd/port の外部サーバは未実装で、シナリオ mocks(宣言的なプロトコル内スタブ、実装済み)で代替する |
config/schema.py MockServer |
web バックエンドでの appTrace 区間証跡 |
appTrace は os_log/simctl 由来(iOS 専用)。Playwright バックエンドは代わりに video と deviceLog 相当(console / page-error)の区間証跡を実装する(BE-0054)が、appTrace に相当するものは持たない |
evidence/intervals.py · drivers/playwright.py |
これらは各機能ページでも該当箇所に「未実装」と注記しています。