| name | make-e2e-live |
| description | e2e-live スイートを継続メンテする。`plans/feat-e2e-live.md` の TODO と直近 main の動向を起点に、未実装シナリオ追加・既存修正・config 改善(webkit project, self-repair 緩和等)を 1 PR で進める skill。実行用の `/e2e-live` skill とは別物。 |
この skill の位置づけ
| skill | 役割 |
|---|
/e2e-live | 既存スイートを 回す(QA / 回帰検出) |
/e2e-live-<category> | 既存カテゴリだけ回す |
/make-e2e-live(このskill) | 既存スイートを 育てる(未実装シナリオ追加 / 修正 / config 改善) |
「実 LLM e2e の追加実装をしたい」 と思ったらこの skill を起点にする。 巨大 PR を避けるため 1 PR = 1〜3 シナリオ or 1 config 改善 に絞ること。
Phase 1: 状況把握
最初に以下をユーザーに見せる前に自分で読む:
plans/feat-e2e-live.md の以下セクション:
- 「実装ステータス」 表(L-01〜L-30 のうち ✅ / 未実装の現状)
- 「直近 main の動向 (#950〜#1000) と本テスト計画への反映」 の 「要対応」 項目
- 「未確定事項 / TODO」 のチェックリスト
plans/survey-e2e-live-test-step-and-nonce.md の以下:
- 「調査タスク」 1〜6 の進捗(plan ファイル上のチェック有無)
- 「各 spec の見立て」 表 —
test.step 化 / testInfo.title nonce 化の横展開候補(PR #1347 で L-15b にのみ適用済、 他 spec への横展開が残 TODO)
- main が最新かを確認 → 必要な場合のみ最新化:
git fetch origin main
git rev-list --count main..origin/main
SSH passphrase が必要な環境では Claude 側から fetch / pull が動かない場合があるので、 失敗したらユーザーに依頼する。
- 前回 e2e-live PR merge 以降の main の動きを確認:
git log main --oneline --since="<前回 merge 日>"
spec の前提を変える PR があれば優先順位を上げる。 過去例:
- #969 / #972 image-path-routing → L-01 assertion 更新
- #982 filePath-only /
/artifacts/html mount → L-01 prompt convention 更新
- #974 onerror self-repair → L-01
naturalWidth > 0 の検出力低下、 緩和策が TODO 残
- #991 Safari preview iframe CSP → webkit project 追加が TODO 残
- ユーザーから chat で追加要望が来ていれば、 上記 4 つに統合する。
Phase 2: 着手項目の自動選定
Phase 1 の結果から、 以下ルールで 1 PR 分の着手項目を自動選定する。 確認待ちで止まらない(auto mode 親和、 ユーザーは Phase 3〜4 進行中いつでも 「やっぱり L-04 で」 と redirect 可)。
PR の規模(1 シナリオ vs 数シナリオ)はユーザー判断。 デフォルトは 1 シナリオ単位、 ユーザーが「カテゴリ別 1 つずつ採取」 や「5-6 個一気に」 と指示したらそれに従う。
選定優先度(上から順に試す)
- C. ユーザー追加要望 — skill 起動プロンプトに項目指定(「L-03 で」 「webkit project 追加」 「カテゴリ別 1 つずつ」 等)があれば最優先で採用
- B. config / 基盤改善 — main 動向の 「要対応」 に未消化があれば 1 つ(webkit project / self-repair 緩和 等)、 もしくは
plans/survey-e2e-live-test-step-and-nonce.md の test infra 横展開(test.step / nonce 化)から 1 spec。 規模が小さく副作用も spec 不変で reversible なので先に消化
- A. 未実装シナリオ —
plans/feat-e2e-live.md の 「実装ステータス」 で未実装のうち、 重要度 S → A → B 順、 同レベル内では番号若い順で 1 つ
モード(C 系の頻出パターン)
- シングルモード(既定): 1 PR = 1 シナリオ。 上記優先度で 1 つ採取
- カテゴリ別採取モード: ユーザーが「カテゴリ 1 つずつ」 「全カテゴリから 1 個ずつ」 等と言ったら、 plan の各カテゴリ(media / roles / session / wiki / ui / skills / docker)から重要度 A 優先・番号若い順で 1 シナリオずつ拾う。 ui / docker は重要度 B / docker-only も多いので、 ユーザー指示で skip 可
- バッチモード: ユーザーが「5-6 個一気に」 「6 シナリオまとめて」 等と言ったら、 PR 規模を ignore してその数だけ author する。 個別 commit を細かく刻んで 1 PR にまとめる流れ
QA 観点で必ず取り込むシナリオ(横串)
mulmoclaude の主要 plugin / 機能で「編集系 (永続化)」 と「未登録系 (リソース不在時の表示)」 は QA で繰り返し発覚しやすい弱点。 シナリオ選定時、 既存 plan に該当エントリが無ければ plan 側に追加して扱う:
- 編集系: 「コンテンツを編集 → 保存ボタンを押す → 別セッション or reload → 戻ったとき編集が残っている」 のフロー検証。 永続化 mech は編集の種類によらず共通なので 代表 1 種 (text 変更等) を 1 spec で見れば mech は満たせる。 編集の種類を全部見たい場合は別 PR で粒度細かく
- 未登録系: 「リソース不在時に UI がどう振る舞うか」 の検証。 機能ごとに spec を 1 本ずつ立てる(audio 未登録時の play / image 未登録時のサムネ / movie 未登録時の Generate ボタン / character 未登録時の thumbnail / 等)。 「壊れる」 が NG、 「適切なエラー UI を出す」 「自然な fallback を取る」 が OK という assertion
issue として #1073 (audio 未登録 → play stall) / #1074 (beat 編集が消える疑い) のように既出のものは spec 化候補として最優先
境界条件
- 現在ブランチが別目的(skill 自身の修正、 別シナリオの作業中、 等)の場合: branch 名と差分から判断し、 同 PR に積めるかを評価。 積めなければ Phase 3 で新 branch を切る前提で進める
- 候補ゼロ(全 ✅)の場合: 「全シナリオ実装済 — main 動向監視 mode へ移行を提案します」 と伝えて終了 → 「保守 mode への自己改修」 セクション発火を提案
- 複数候補が引き分け(例: 重要度 A の未実装が並ぶ): 番号若い順で 1 つに決める。 迷わない
Phase 3 へ移る前のログ出力(必須)
着手: <項目(例: B1 webkit project 追加 / L-05 generateImage 実画像)>
理由: <選定根拠(例: PR #991 要対応かつ未実装 / B カテゴリ空のため A 最高優先度を採用)>
PR 規模: <小 / 中 / 大>
ブランチ方針: <新規 feat/e2e-live-<topic> を切る / 既存 <branch> に積む>
このログを出してから Phase 3 へ自動的に進む。 ユーザーが redirect したい場合はこのログ表示の隙間に介入できる(Phase 3 の git checkout 前で一拍置く程度の感覚で OK)。
Phase 3: ブランチ準備
Phase 2 で決めた 「ブランチ方針」 に従う。
新規ブランチを切る場合
git checkout main && git pull --ff-only
git checkout -b feat/e2e-live-<topic>
<topic> は内容を表す短い英語(例: l03-movie-dl, webkit-project, self-repair-guard)。 SSH passphrase が必要な環境では pull は Claude 側から動かないので、 失敗したらユーザーに依頼する。
既存ブランチに積む場合
ユーザーが 「この branch のまま」 と指示している、 もしくは Phase 2 の 「ブランチ方針」 で 「既存に積む」 を選定したケース。 何もしない(現在ブランチで Phase 4 へ)。 ただし以下のリスクをログに残す:
- PR scope が混ざる(例: skill 追加 PR に L-XX spec 実装を相乗り)
- 同 PR の review 範囲が広がり、 bot レビューで指摘が増える可能性
ユーザーが意図的にそうしている場合は問題なし。 不意に積まれていそうなら一度確認する。
Phase 4: 実装
既存パターンを踏襲する。 plans/feat-e2e-live.md の 「実装の詳細」 セクションが詳細仕様。
Step 0: testid 洗い出し(spec を書き始める前に必ず)
このステップを後回しにすると、 spec 内に getByText('日本語ラベル') / locator('.tw-xxxx') のような i18n / class 依存 selector が残り、 翻訳変更や Tailwind class rename で壊れる。 最初の page.locator(...) / page.click(...) を書く前に 必ず通る関門として扱う。
先に読むべき docs:
手順:
- spec で触る予定の UI 要素を箇条書きで洗い出す(input / button / iframe / preview / thumbnail / 等)
- それぞれが既に
data-testid を持っているかを確認(ui-cheatsheet → grep の順):
grep -rn "data-testid" src/ | grep -i "<keyword>"
- 不足分は spec を書き始める前に 同 PR 内で先に追加:
- source に
data-testid="<plugin>-<role>" を追加(kebab-case、 例: audio-play-button / image-thumbnail)
- 機能名で付ける — 位置(
top-right-button)、 文言(save-button の "Save" ラベル直訳)、 構造(first-row-cell)は NG
docs/ui-cheatsheet.md の該当 ASCII ブロックを更新(CLAUDE.md ルール)
- 翻訳テキストや
iframe[sandbox] 構造属性に依存しない(脆い)
- testid 追加は spec 実装と独立した commit に切る(review しやすくするため)
「あとでまとめて付ける」 にしないこと — spec 実装中に「ここ testid 無いな」 と気づいた時点で その場で Step 0 に戻る。
共通ルール
- helper の追加先:
- 複数 spec で再利用するもの →
e2e-live/fixtures/live-chat.ts
- その spec 内だけで使うもの → spec 内 local function
- workspace 配置 / cleanup:
- 配置:
placeFixtureInWorkspace(fixtureRel, workspaceRel)
- 削除:
removeFromWorkspace(workspaceRel) を必ず finally で呼ぶ
- workspace path に spec 名を含めて並列衝突を回避(例:
artifacts/images/e2e-live-l03.png)
- session cleanup:
getCurrentSessionId(page) + deleteSession(page, sessionId) を finally で
- iframe 内 DOM:
frameLocator API を使う — page.evaluate + iframe.contentDocument は Vue の srcdoc 更新で古い document を返す罠
- iframe
toBeVisible だけでは早すぎる。 内側の特定要素を frameLocator(...).locator(...) で待つ
- assertion 達成後に
waitForAssistantResponseComplete(page) を呼ぶ — 呼ばないと trace / video が応答途中で切れる
- testid 新設時: Step 0 を参照(命名規約 /
docs/ui-cheatsheet.md 更新 / 脆い selector 回避)
- 新規テスト追加時は
docs/e2e-live-testing.md の skip 規約に従う — Claude 必須テストには per-test で test.skip(process.env.E2E_LIVE_NO_LLM === "1", ...) を付ける
- 新規 spec ファイル追加時は
.github/workflows/e2e_live_no_llm.yaml の matrix.spec: への登録も併せて確認する(1 本でも fake-friendly なテストがあれば追加)
コーディングルール(CLAUDE.md より)
- 関数 20 行以内、 超えたら分割
const 優先、 var 禁止
- non-null assertion
! 禁止 → if (x === null) throw new Error(...) で type narrowing
- パス組み立ては
node:path の path.join / path.resolve、 / 直書き禁止
as キャスト禁止 → type guard で narrowing
- 全
fetch に try/catch + !response.ok チェック
必須チェック(commit 前 / push 前に毎回実行)
yarn format
yarn lint
yarn typecheck:e2e-live
yarn build
yarn test:e2e:live:<category>
yarn test:e2e:live:<category> は実 Claude API を叩くので、 ユーザーに yarn dev 起動済みか / 認証 OK か確認してから走らせる。
注意 — dev server の stale: yarn dev の server プロセスは tsx server/index.ts(--watch なし)で起動するため、 server/*.ts や server に取り込まれる src/utils/** の変更は再起動するまで反映されない。 git pull で main を更新した直後・branch を切り替えた直後に走らせると、 ソース上は修正済の bug が再発したように見える(実例: PR #991 後の webkit L-01 fail → 誤った issue #1015 起票、 dev 再起動だけで解消)。 走らせる前にユーザーに 「dev 再起動済か?」 を 1 回確認する。
test fail を見たときの鉄則
-
fail trace を 再走前に rename して保存する — Playwright は outputDir を毎 run の冒頭で clean するので、 fail を見たまま再走すると trace.zip / video / screenshot / error-context.md が 永久に消える。 「もう一回走らせれば pass するかも」 で trace を捨てない。 例:
FAILED_DIR=$(ls -td test-results-live/<category>/*-<project>/ 2>/dev/null | head -1)
cp -r "$FAILED_DIR" "/tmp/e2e-live-fail-$(date +%s)"
保存してからでないと「なぜ fail したか」 を再現できない。 push してから CI で同じ症状が出ても、 ローカルの trace が無いと triage 不能。
-
PW report を先に見る、 source 漁りは最後 — fail の原因切り分けは playwright-report-live/<category>/index.html か trace.zip の 0-trace.network (HTTP status / response body) → 0-trace.trace (ステップとアサーション) → 失敗時 screenshot / video → error-context.md の page snapshot、 の順で見る。 これらに答えが無いことを確認してから初めて source code を grep する。 source 先行は推測ベースの triage を生み、 「環境負荷のせい」 のような根拠の無い結論に流れる。
-
「ホスト負荷 / dev server stale / flake」 を結論にしない — それらは可能性の一つで、 trace の HTTP status と response body を見て初めて支持される仮説。 trace を保全せずに 「load avg 高いから transient」 と決めつけるのは、 user の時間と CI の時間の両方を浪費する。 本当に flake と分かったあとも、 何回連続 pass で flake と判定したか / どの response body が決め手になったか をログに残す。
Docker on / off
このメンテ skill では基本 片モードだけ で OK。 「両モード巡回」 は実行用 /e2e-live の責任なので、 メンテ中は手元の dev のモードで pass まで持っていけば十分。 PR で「両モードで pass 確認した」と書く必要があれば、 commit 前にユーザーに DISABLE_SANDBOX 切替を依頼する。
Phase 5: commit / push / PR / bot 対応
- commit はこまめに(schema 追加 → commit、 helper 追加 → commit、 spec 1 本 → commit)
- commit message: 英語、 prefix
feat: / fix: / refactor: / docs: / chore:
git add . 禁止 — 個別ファイル追加
- push は 必ずユーザー依頼(SSH 認証は Claude 側で動かない)
- push 完了後に
gh pr create:
- title: 英語、 70 文字以内
- body: 日本語、 冒頭に Summary + Items to Confirm / Review を置く(CLAUDE.md ルール)
- User Prompt セクションを含める(このセッションでのユーザー指示を要約)
- 個人名 / 生コメントの混入禁止 — 匿名化する
- push 後は
/coderabbit-review skill で CodeRabbit / Sourcery / 他 bot コメントをトリアージ
Phase 6: plans 反映
同 PR 内で plans/feat-e2e-live.md を更新:
- 実装したシナリオを 「実装ステータス」 表で ✅ 化(備考に「.spec.ts、 <要点>」 を 1 行)
- 「未確定事項 / TODO」 のうち解消したものは消す or 「→ PR #XXX で解消」 に書き換え
- 「直近 main の動向」 の 「要対応」 から取り込んだ項目は 「反映済」 に移動
これは別 PR にせず 同 PR でセットコミット。 ステータスとコードを必ず同期させる。
保守 mode への自己改修(全シナリオ実装後)
「実装ステータス」 表が L-01〜L-30 全 ✅(うち L-25 / L-27 は manual-l4 として docs/manual-testing.md に移動済)になったら、 この skill を保守用に縮める:
- Phase 1 の手順 1 から 「実装ステータス」 行を削除(読むのは「直近 main の動向」 と「TODO」 だけで十分)
- Phase 2 着手候補の 「A. 未実装シナリオ」 セクションを削除(B / C のみ残す)
- description を 「e2e-live スイートの保守。 main の動向起点で既存シナリオ修正・config 改善を行う」 に書き換え
この自己改修も同 PR でコミットする。 plans 側の Status と skill 側の挙動を同時に切替えるのが合流ポイント。
アンチパターン
- ❌ helper を spec 内に書いてから「あとで fixtures に切り出す」 — そのまま放置されて重複が増える。 「2 spec で使う」 が見えた時点で切り出す
- ❌
mockAllApis(page) を呼ぶ — このスイートは実 LLM 経路の検証が目的、 mock すると意味がない
- ❌ 応答テキストでの assertion — LLM 揺れに弱い。 DOM 状態(visible /
naturalWidth / src 属性 / download magic bytes)で見る
- ❌
assert(x !== null); use(x!) の non-null assertion — if (x === null) throw new Error(...) で narrow
- ❌ webkit project を追加するときに spec を変えに行く — config 追加だけで pass / fail が分かれるので、 まず config 追加 → 別 PR で spec 側調整
参照
plans/feat-e2e-live.md — 設計仕様 / 実装ステータス / 内部バグ ID 対応表
plans/survey-e2e-live-test-step-and-nonce.md — test.step / testInfo.title nonce の横展開調査 plan(PR #1347 で L-15b にのみ適用済)
e2e-live/fixtures/live-chat.ts — 既存 helper 一覧
e2e-live/tests/media.spec.ts — L-01 / L-02 の参考実装
docs/ui-cheatsheet.md — testid 追加時に併せて更新
docs/e2e-live-testing.md — e2e-live オーサリング規約(2 backend / fake-echo 対応表 / skip 作法、必読)
CLAUDE.md — コーディングルール / git 運用 / PR フォーマット