Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ playwright-report/
test-results/
.wrangler/
.bithub/
vrt/test-results/
vrt/baselines/
vrt/snapshots/
vrt/output/
vrt/vrt-report.json
vrt/node_modules/
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,25 @@ bit core /Users/mz/ghq/github.com/bit-vcs/bit
## Cloudflare Entrypoint

`src/cmd/main/main.mbt` exports `fetch(request, env, exec_ctx)` and delegates to `@mars.Server::to_handler_with_env`. Page rendering lives in `src/adapters/mars_http/server.mbt`, using `@sol.render_page` + `mizchi/luna/x/components` for SSR.

### Cloudflare Artifacts browse adapter

`worker-entry.js` binds the test namespace `bit-vcs-playground` as `ARTIFACTS`. The read-only
adapter keeps Git credentials in the Worker and exposes raw Artifacts metadata instead. The binding
uses `remote = true`, so `wrangler dev` accesses the real test namespace:

- `GET /api/artifacts/repos`
- `GET /api/artifacts/repos/<repo>/log?ref=main&limit=20&offset=0`
- `GET /api/artifacts/repos/<repo>/commits/<sha>`
- `GET /api/artifacts/repos/<repo>/trees/<sha>`

These endpoints remain disabled until a dedicated secret is configured. This prevents the default
public read UI from accidentally exposing a private Artifact repository:

```bash
pnpm wrangler secret put BITHUB_ARTIFACTS_READ_TOKEN
```

Call them with `Authorization: Bearer $BITHUB_ARTIFACTS_READ_TOKEN`. The adapter only calls
`list`, `log`, `readCommit`, and `readTree`; it never creates Git tokens, writes repository data, or
replaces bithub's R2-backed issue/PR/CI state.
18 changes: 18 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ Last updated: 2026-03-17
- [ ] Add `moon_ide` tool wrapping `moon ide peek-def` and `moon ide outline`
- More accurate than grep for MoonBit symbol lookup

### VRT + Semantic Verification

- [ ] Multi-step goal runner: 大きなゴールを分解して複数コミットで達成するシナリオテスト
- Goal → sub-tasks に分解 → 各 sub-task で expectation 生成 → 逐次実行 → ゴール達成を判定
- 例: "ダークモード対応" → テーマ変数追加 → コンポーネント適用 → VRT 全ページ verify
- ランナー設計: `GoalRunner { goal, steps: Step[], currentStep, accumScore }`
- 各 step: expectation.json 自動生成 → subagent 実行 → verify → score → 次の step へ
- 失敗時: 修正ループ (max 3 retry) or ゴール縮小
- 最終スコア: step 成功率 × 品質スコア × (1 / トークン消費)
- [ ] Playwright テストヘルパ: テスト失敗時のみ AI アサーション発火
- `nlAssert(page, "ナビに5つ以上リンクがある", { onlyOnFailure: true, dependsOn: ["src/Header.tsx"] })`
- 失敗時: Vision LLM でスクリーンショット分析 → 修正ヒント → エージェントに投げる
- dep graph 連携で影響のないアサーションをスキップ
- [ ] introspect CLI コマンド: `vrt introspect` → spec.json 自動生成
- [ ] spec verify CLI コマンド: `vrt spec-verify` → long-cycle 不変条件の検証
- [ ] form/region ランドマークの spec invariant 自動生成 (現状 banner/main/nav のみ)
- [ ] role-changed の spec 検出 (現状は a11y diff でのみ検出)

### Remaining features

- [ ] Enable Container orchestration in wrangler.toml
Expand Down
128 changes: 128 additions & 0 deletions docs/vrt-research.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# VRT (Visual Regression Testing) + AI 調査メモ

## 動機

VRT で検出した差分を AI でリーズニングし、自己修復を行うアーキテクチャを検討する。
ただしコストが高いため、以下で最適化したい:

1. **依存ツリー解析** — 変更の影響範囲を絞り込み、スナップショット対象を最小化
2. **意図とのすり合わせ** — commit/PR の変更意図と視覚差分を照合し、期待通りの変更を自動承認

---

## 1. 既存ツール・プラグインの状況

### AI-Powered VRT (商用)

| ツール | アプローチ | 特徴 |
|--------|-----------|------|
| **Applitools Eyes** | 独自 Visual AI (CV ベース) | UI をセマンティックに理解。レンダリングノイズを無視。最も成熟 |
| **Percy Visual Review Agent** (BrowserStack) | スマートハイライト + 説明文生成 | 「ヘッダーが4px左にずれた」等の自然言語差分。偽陽性40%削減。人間承認は必要 |
| **Meticulous AI** | セッションリプレイ | ユーザ操作を記録→再生。静的スクリーンショットではなくフロー単位 |
| **TestMu SmartUI** | ピクセル + ヒューリスティクス | ルールベースの Smart Ignore (フォントレンダリング等) |

### 依存ツリー対応 VRT

| ツール | アプローチ | 特徴 |
|--------|-----------|------|
| **Chromatic TurboSnap** | Webpack/Vite Stats → モジュール依存グラフ | 変更ファイル → 影響 Story をマッピング。60-90% のスナップショット削減。**唯一の実装** |

### OSS VRT ツール (ピクセルベース)

- **Playwright** built-in VRT (pixelmatch)
- **Lost Pixel** — Storybook/Ladle 対応
- **BackstopJS** — ビューポート/シナリオ設定
- **reg-suit / reg-cli** — CI 統合・レポート生成
- **Visual-Regression-Tracker** — セルフホスト。実験的 VLM サポートあり

### ギャップ (未開拓領域)

1. **LLM ベース VRT リーズニング**: スクリーンショット差分を Vision LLM に送り判定する OSS ツールは**存在しない**
2. **依存ツリー対応 VRT**: Chromatic TurboSnap の独占。Vite 単独や任意フレームワークで使える OSS 代替なし
3. **Intent-aware VRT**: コミットメッセージ/PR 記述から変更意図を抽出し、視覚差分と照合する仕組みは**完全に未開拓**

---

## 2. 関連論文

### VRT 方法論・最適化

- Moradi et al. (2024) — **"AI for Context-Aware Visual Change Detection"** [arXiv:2405.00874](https://arxiv.org/abs/2405.00874)
- YOLOv5 で UI コントロールを検出 → グラフ構築 → 空間的文脈から意味のある変更を判定。ピクセル/リージョン比較より優秀
- Web Application Testing Survey (2024) [arXiv:2412.10476](https://arxiv.org/abs/2412.10476)
- 2014-2023 の Web テスト研究サーベイ

### 依存対応テスト選択

- **DIRTS** (ICST 2023) — DI フレームワーク対応の Regression Test Selection
- **Lam et al.** (ISSTA 2020) — 順序依存テストの優先付け・選択・並列化。依存対応アルゴリズムで失敗 80% 削減
- **CORTS/C2RTS** (2025, J. Systems Architecture) — コンポーネントベース RTS。モジュールレベル依存グラフ

### Self-Healing テスト自動化

- Chede & Tijare (2025, IJRASET) — **"AI-Driven Self-Healing UI Testing with Visual Proof"**
- DOM ベースのヒーリングとセマンティック視覚検証の統合
- Self-Healing Test Automation with AI/ML (2024) — RL + 画像認識 + 動的ロケータ
- **SHML** (NeurIPS 2024) [arXiv:2411.00186](https://arxiv.org/abs/2411.00186) — 自律的診断・修復フレームワーク

### LLM/Vision モデル × テスト

- **Wang et al.** (TSE 2024) — LLM × ソフトウェアテスト 102 研究のサーベイ [arXiv:2307.07221](https://arxiv.org/abs/2307.07221)
- **VisionDroid** (2024) [arXiv:2407.03037](https://arxiv.org/abs/2407.03037) — マルチモーダル LLM で GUI 探索 + 非クラッシュバグ検出
- **Make LLM a Testing Expert** (ICSE 2024) — 機能認識に基づくモバイル GUI テスト
- **RepairAgent** (ICSE 2025) — LLM ベースの自律プログラム修復エージェント
- Yu et al. (ACM Computing Surveys, 2025) — Vision-Based Mobile GUI Testing サーベイ [arXiv:2310.13518](https://arxiv.org/abs/2310.13518)

### 参考リポジトリ

- [LLM4SoftwareTesting](https://github.com/LLM-Testing/LLM4SoftwareTesting) — LLM × テスト論文キュレーション
- [GUI-Agents-Paper-List](https://github.com/OSU-NLP-Group/GUI-Agents-Paper-List) — GUI エージェント論文一覧

---

## 3. 考察: 本プロジェクトへの適用可能性

### 構想: 依存ツリー + Intent-aware + AI リーズニングの統合

```
Code Change
├─ 1. 依存ツリー解析 (低コスト)
│ Vite モジュールグラフ / コンポーネント import 解析
│ → 影響を受けるコンポーネント/ページを特定
│ → VRT スナップショット対象を最小化 (TurboSnap 相当)
├─ 2. Intent 抽出 (低〜中コスト)
│ commit message / PR description を LLM でパース
│ → 「ボタンの色を青→緑に変更」等の期待変更を構造化
├─ 3. VRT 実行 (中コスト)
│ 最小化されたスナップショット対象のみ撮影・比較
└─ 4. AI リーズニング (高コスト、条件付き)
Intent と一致する差分 → 自動承認
Intent と不一致 or 予期しない差分 → Vision LLM で分析
→ 修復提案 or 人間レビューにエスカレート
```

### コスト最適化のポイント

1. **段階的フィルタリング**: 依存ツリー → Intent 照合 → AI 判定 の順で、安価なフィルタから先に適用
2. **AI 呼び出しの最小化**: 全差分を LLM に送るのではなく、自動承認できないものだけを AI に渡す
3. **キャッシュ**: 同一コンポーネントの類似差分パターンをキャッシュし、再判定を回避

### 技術的課題

- Vite モジュールグラフの取得方法 (TurboSnap は Webpack Stats API 依存)
- Intent 抽出の精度 (自然言語→構造化された期待変更の変換)
- Vision LLM のコスト vs 精度のトレードオフ
- self-healing の信頼性 (自動修復が意図しない変更を入れるリスク)

---

## 4. 次のステップ

- [ ] Vite プラグインとしての依存ツリー取得 PoC
- [ ] Playwright VRT + LLM リーズニングの最小プロトタイプ
- [ ] Intent 抽出プロンプトの設計
- [ ] コスト試算 (スナップショット数 × LLM API コスト)
21 changes: 9 additions & 12 deletions e2e/commits-branches.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,15 @@ test.describe('blame view', () => {
});
});

test.describe('navigation', () => {
test('nav bar has commits and branches links', async ({ page }) => {
test.describe('workspace landing page', () => {
test('prompts to open a repository before showing repository navigation', async ({ page }) => {
await page.goto('/');
const nav = page.getByRole('navigation', { name: 'primary navigation' });
await expect(nav.getByRole('link', { name: 'commits' })).toBeVisible();
await expect(nav.getByRole('link', { name: 'branches' })).toBeVisible();
});

test('home page has commits and branches in feature list', async ({ page }) => {
await page.goto('/');
const main = page.getByRole('main');
await expect(main.getByRole('link', { name: 'commits' })).toBeVisible();
await expect(main.getByRole('link', { name: 'branches' })).toBeVisible();
await expect(
page.getByRole('heading', { level: 2, name: 'Open Repository' }),
).toBeVisible();
await expect(page.locator('#ws-repo')).toBeVisible();
await expect(
page.getByRole('button', { name: 'Clone & Open' }),
).toBeVisible();
});
});
19 changes: 10 additions & 9 deletions e2e/features.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,18 @@ test.describe('compare', () => {
});

// ---------------------------------------------------------------------------
// Navigation includes new links
// Workspace landing page
// ---------------------------------------------------------------------------
test.describe('navigation', () => {
test('nav bar includes issues, activity, search', async ({ page }) => {
test.describe('workspace landing page', () => {
test('prompts to open a repository before showing repository navigation', async ({ page }) => {
await page.goto('/');
const nav = page.getByRole('navigation', {
name: 'primary navigation',
});
await expect(nav.getByRole('link', { name: 'issues' })).toBeVisible();
await expect(nav.getByRole('link', { name: 'activity' })).toBeVisible();
await expect(nav.getByRole('link', { name: 'search' })).toBeVisible();
await expect(
page.getByRole('heading', { level: 2, name: 'Open Repository' }),
).toBeVisible();
await expect(page.locator('#ws-repo')).toBeVisible();
await expect(
page.getByRole('button', { name: 'Clone & Open' }),
).toBeVisible();
});
});

Expand Down
5 changes: 3 additions & 2 deletions e2e/mars-http.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ test('home route is available', async ({ page }) => {
expect(response).not.toBeNull();
expect(response!.status()).toBe(200);
await expect(page.getByRole('heading', { level: 1, name: 'bithub' })).toBeVisible();
await expect(page.getByRole('link', { name: 'README.md' })).toBeVisible();
await expect(page.getByRole('link', { name: 'files' })).toBeVisible();
await expect(page.getByRole('heading', { level: 2, name: 'Open Repository' })).toBeVisible();
await expect(page.locator('#ws-repo')).toBeVisible();
await expect(page.getByRole('button', { name: 'Clone & Open' })).toBeVisible();
});

test('healthz returns ok', async ({ request }) => {
Expand Down
13 changes: 9 additions & 4 deletions e2e/pulls-webhooks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,15 @@ test.describe('webhook log', () => {
});

// ---------------------------------------------------------------------------
// Navigation
// Workspace landing page
// ---------------------------------------------------------------------------
test('nav includes pulls link', async ({ page }) => {
test('workspace landing page prompts to open a repository', async ({ page }) => {
await page.goto('/');
const nav = page.getByRole('navigation', { name: 'primary navigation' });
await expect(nav.getByRole('link', { name: 'pulls' })).toBeVisible();
await expect(
page.getByRole('heading', { level: 2, name: 'Open Repository' }),
).toBeVisible();
await expect(page.locator('#ws-repo')).toBeVisible();
await expect(
page.getByRole('button', { name: 'Clone & Open' }),
).toBeVisible();
});
69 changes: 68 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ check:
moon check --target js

test:
moon test --target js
moon test --target js --package bithub
just test-artifacts

test-artifacts:
node --test tests/artifacts_api.test.mjs

build:
moon build --target js
Expand Down Expand Up @@ -70,6 +74,69 @@ agent-parallel:

# ---- Workflow: Issue → Agent → Done ----

# ---- VRT (Visual Regression + Semantic Testing) ----

# Initialize VRT baselines (requires running server)
vrt-init:
npx tsx vrt/src/vrt-cli.ts init

# Capture current VRT snapshots
vrt-capture:
npx tsx vrt/src/vrt-cli.ts capture

# Verify VRT snapshots against baselines
vrt-verify:
npx tsx vrt/src/vrt-cli.ts verify

# Accept current snapshots as new baselines
vrt-approve:
npx tsx vrt/src/vrt-cli.ts approve

# Show VRT report
vrt-report:
npx tsx vrt/src/vrt-cli.ts report

# Show affected components
vrt-affected:
npx tsx vrt/src/vrt-cli.ts affected

# Generate spec.json from current state
vrt-introspect:
npx tsx vrt/src/vrt-cli.ts introspect

# Verify spec.json invariants
vrt-spec-verify:
npx tsx vrt/src/vrt-cli.ts spec-verify

# Auto-generate expectation.json from diff
vrt-expect:
npx tsx vrt/src/vrt-cli.ts expect

# Run VRT demo (kitty graphics)
vrt-demo:
npx tsx vrt/src/demo.ts

# Run fix loop demo (detect → reason → fix → verify)
vrt-demo-fix:
npx tsx vrt/src/demo-fix-loop.ts

# Run multi-scenario demo (3 complex scenarios)
vrt-demo-multi:
npx tsx vrt/src/demo-scenarios.ts

# Run 6-step dashboard rebuild demo
vrt-demo-multistep:
npx tsx vrt/src/demo-multistep.ts

# Run VRT unit tests
vrt-test:
cd vrt && node --test --experimental-strip-types src/**/*.test.ts

# Full VRT cycle: capture + verify
vrt: vrt-capture vrt-verify

# ---- Workflow: Issue → Agent → Done ----

# Full workflow: create issue, run daemon once
auto title body="":
#!/usr/bin/env bash
Expand Down
26 changes: 16 additions & 10 deletions moon.mod.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
{
"name": "bit-vcs/bithub",
"version": "0.1.1",
"version": "0.1.2",
"deps": {
"moonbitlang/async": "0.16.8",
"mizchi/mars": "0.3.9",
"mizchi/bit": "0.37.0",
"mizchi/markdown": "0.4.7",
"mizchi/luna": "0.16.0",
"moonbitlang/x": "0.4.41",
"mizchi/js": "0.10.14",
"mizchi/sol": "0.12.0"
"moonbitlang/async": "0.20.3",
"mizchi/mars": "0.3.11",
"mizchi/bit": "0.45.1",
"mizchi/markdown": "0.6.2",
"mizchi/luna": "0.23.3",
"moonbitlang/x": "0.4.47",
"mizchi/js": "0.12.1",
"mizchi/sol": "0.23.2",
"mizchi/bit_lib": "0.45.1",
"mizchi/bit_vfs": "0.45.1",
"mizchi/bitx_hub": "0.45.1",
"mizchi/bit_core": "0.45.1",
"mizchi/bit_types": "0.45.1",
"mizchi/bit_object": "0.45.1"
},
"readme": "README.md",
"repository": "https://github.com/bit-vcs/bithub",
Expand All @@ -23,4 +29,4 @@
"description": "GitHub-like UI backend for bit",
"source": "src",
"preferred-target": "js"
}
}
Loading
Loading