Skip to content
Merged
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
11 changes: 6 additions & 5 deletions .agents/rules/common.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@

**E2E テストは実装と同時に書く**: バグ修正・UI 挙動の変更時はコミット前に該当ケースの E2E を追加する。後回し禁止。

**push 前に必須**: `npm run test`(ユニット)/ `node_modules/.bin/astro check`(型)/ `npm run test:e2e`(E2E)。
post-PR 代行は不要、CI が最終ゲート。
**push 前に必須**: `npm run format:check`(整形)/ `npm run test`(ユニット)/ `node_modules/.bin/astro check`(型)/ `npm run test:e2e`(E2E)。
post-PR 代行は不要、CI が最終ゲート。**`format:check` を含める理由**: CI の `test` ジョブは `format:check` を最初に走らせるため、`npm run test` だけでは整形崩れ(特に `Write` / `Edit` で作成した Markdown)を検出できず CI が赤になる(PR #753 実例)。

**ガード / バリデータ / 検知機構には陽性対照を必須**: 検出する・拒否する・違反したら fail させる仕組み(CSP 違反検知 / 入力 validator / lint / セキュリティヘッダ assert / E2E ガード / regex マッチ系)を追加 / 修正する場合は **`Skill` tool で `test-gates` skill を必ず呼ぶ**。陰性対照のみでは「検知能力ゼロで green」と区別不能(PR #233 `applyProductionCsp` 空回り事故)。詳細・チェックリストは skill 本体に集約してこの doc では肥大化させない。

Expand Down Expand Up @@ -70,9 +70,10 @@ post-PR 代行は不要、CI が最終ゲート。
1. `src/components/tools/ToolName.tsx` を作成
2. `src/pages/tools/tool-slug.astro` を作成(`client:load` で React コンポーネントをマウント)
3. `src/data/tools.ts` の `toolEntries` 配列にエントリを追加(slug / name / description / category / yomi)。`yomi` は並び替え用の読み仮名(ひらがな)で、表示順はこの `yomi` の五十音順に自動ソートされる(手動で位置を決める必要はない)
4. `tests/e2e/visual-regression-pages.ts` の `PAGES` 配列に `/tools/<slug>` を追加(VRT 対象に登録)。baseline は CI Linux runner で `Update Visual Regression Baseline` workflow を `workflow_dispatch` trigger して生成(mac との font 描画差を回避するためローカル生成は不可)。**漏れた場合は `tests/meta/vrt-pages-coverage.test.ts` が `npm run test` で fail させる**ため CI で必ず検知される(issue #355 で導入)。※ この `workflow_dispatch` をエージェント自身が起動できるかは実行環境のトークン権限に依存する(Claude Code on the web では `actions: write` が無く起動不可・手動トリガー必須 → `.claude/rules/github-web-session.md`。他エージェントは各固有ルール参照)。
5. 4 章「ドキュメント更新ルール」に従い `README.md` / `SPEC.md` / `docs/decisions.md` を更新
6. 候補リスト(`docs/tool-candidates.md`)由来のツールの場合、PR マージ時に該当行の「状態」列へ ✅ と PR 番号を記載する
4. `src/components/ui/ToolIcon.astro` にツールアイコン(SVG)を追加する。既存アイコンと同じ `{...attrs}` 展開・`currentColor` 方式に従う。**漏れた場合は `tests/meta/tool-icon-coverage.test.ts` が `npm run test` で fail させる**(PR #746 で漏れが発生し手戻りになった実例あり)
5. `tests/e2e/visual-regression-pages.ts` の `PAGES` 配列に `/tools/<slug>` を追加(VRT 対象に登録)。baseline は CI Linux runner で `Update Visual Regression Baseline` workflow を `workflow_dispatch` trigger して生成(mac との font 描画差を回避するためローカル生成は不可)。**漏れた場合は `tests/meta/vrt-pages-coverage.test.ts` が `npm run test` で fail させる**ため CI で必ず検知される(issue #355 で導入)。※ この `workflow_dispatch` をエージェント自身が起動できるかは実行環境のトークン権限に依存する(Claude Code on the web では `actions: write` が無く起動不可・手動トリガー必須 → `.claude/rules/github-web-session.md`。他エージェントは各固有ルール参照)。**baseline 生成 workflow は対象ブランチへ直接コミットを push する**ため、実行後にローカルから push する場合は先に `git pull --rebase origin <branch>` で取り込むこと(取り込まないと non-fast-forward で拒否される)
6. 4 章「ドキュメント更新ルール」に従い `README.md` / `SPEC.md` / `docs/decisions.md` を更新
7. 候補リスト(`docs/tool-candidates.md`)由来のツールの場合、PR マージ時に該当行の「状態」列へ ✅ と PR 番号を記載する

新しい入力欄・ボタン・エラー表示等を実装する前に、`src/components/ui/` の既存共通コンポーネント(`InputField`, `CopyButton`, `DownloadButton` 等)を確認すること。一覧と用途は `.agents/rules/ui-conventions.md` を参照。

Expand Down
16 changes: 16 additions & 0 deletions .agents/rules/ui-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ input / textarea / button などのフォーカス可能要素の className に
| 操作の種類が変わる(エンコード/デコード等) | する | 入力の期待形式が変わる |
| 同じ操作のサブバリアント(標準/URL-safe 等) | しない | 出力比較のために保持が便利 |

### 2.5 live region(`aria-live` / `role="status"`)は小さい要素に限定する

リアルタイム変換系ツールで **結果領域全体**(サマリ・詳細・テーブルを含む大きな div)に `aria-live` / `role="status"` を付けない。入力を 1 文字編集するたびに領域全体が変化し、スクリーンリーダーに膨大な再アナウンスが走る。

- ✅ 推奨: 「変換ステップ行」「結果の 1 行要約」など**小さく安定した要素**だけを live region にし、詳細領域は通常のセクションにする
- `role="status"` は暗黙で `aria-live="polite"` を持つため、両方を併記しない(冗長)
- 過去事例: PR #746 のレビューで検出(JwtDecoder の既存パターンを踏襲した結果の再発。既存分の改修は別 issue 管理)

---

## 3. Playwright での確認手順
Expand All @@ -130,3 +138,11 @@ UI 変更時は **PC (1280x800)** と **スマホ (390x844)** 両方でスクリ

- `getByRole` / `getByText` / `getByLabel` を使う。`locator('[role="X"]')` のような属性セレクタは禁止(アクセシビリティ・国際化に弱く、リファクタリング耐性も低い)。
- DOM 直接操作(`page.evaluate`)より `expect` のオートリトライを優先(React の再レンダータイミングで不安定になるため)。

### 3.4 React island へ入力する E2E spec は hydration 待機が必須

React island(`client:load` でマウントされるツール本体)に `fill` / `click` 等で入力する spec は、**`beforeEach` で `await waitForReactHydration(page);`(`tests/e2e/helpers.ts`)を必ず呼ぶ**。

- hydration 完了前の `fill` は DOM の value だけを書き換え、React の `onChange` が発火しないため state が空のまま進む(例: URI 貼り付け分解で一部フィールドだけ空になる)
- この race は **CI では顕在化しない**(`workers: 1` の直列実行で hydration が間に合う)が、ローカルの並列実行で flaky になる。「CI green だからテストは正しい」とは判断できない
- 過去事例: issue #750(`dsn-builder.spec.ts` / `dummy-personal-data.spec.ts` が未呼び出しでローカル 8〜10 件 fail)
2 changes: 1 addition & 1 deletion .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
| grill-me | [mattpocock/skills](https://github.com/mattpocock/skills) | MIT([LICENSE-mattpocock-skills](./LICENSE-mattpocock-skills)) |
| vercel-react-best-practices | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) | MIT(upstream に LICENSE ファイルは無く [README](https://github.com/vercel-labs/agent-skills#license) で MIT 宣言) |
| frontend-design | [anthropics/claude-plugins-official](https://github.com/anthropics/claude-plugins-official)(`plugins/frontend-design`) | Apache-2.0([LICENSE-frontend-design](./LICENSE-frontend-design)) |
| dads-design-system / test-gates | 本リポジトリ自作 | 本リポジトリのライセンスに従う |
| dads-design-system / test-gates / retro | 本リポジトリ自作 | 本リポジトリのライセンスに従う |
56 changes: 56 additions & 0 deletions .agents/skills/retro/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: retro
description: PR マージ後の振り返り(retro / レトロ / 振り返り)。対象PRの作業から気づき(手戻り・レビュー指摘・つまずき)を、レビューコメント・docs/agent-lessons.md・会話履歴の3ソースから抽出し、.agents/rules/common.md 11 章の基準で5分類に仕分けして、承認された分だけドキュメント改善PRを作る。ユーザーが `/retro`、「振り返り」「レトロ」「retro して」等と言ったとき発動。手動起動が主で、対象PRは引数指定または直近マージPR。
---

# retro: PR マージ後の振り返りをドキュメント改善に落とす

PR マージ後に、そのPRの作業から得られた気づきを抽出し、.agents/rules/common.md 11 章の基準で仕分けして、
**再発防止に値するものだけ**をドキュメント改善PRに落とす手順。

自動分析が暴走して無関係な変更を提案しないよう、判定基準は厳格に。過剰な提案は形骸化を招くため
YAGNI 寄りに倒し、Step 4 で必ず停止してユーザー承認を挟む。

## Step 1 — 対象PRの特定

- `/retro [PR番号]` の引数があればそれを対象にする。
- 引数省略時は直近マージPR(`gh pr list --state merged --limit 1 --json number,title`)を取得し、
**「PR #N(タイトル)を対象にします。よいですか?」と確認してから**進む(誤爆防止)。

## Step 2 — 3ソース収集(会話履歴は best-effort)

- **レビューコメント(主軸)**: `gh pr view <N> --comments`
- **既存教訓(主軸)**: `docs/agent-lessons.md` を読み、繰り返し出ている教訓を把握
- **会話履歴(best-effort)**: 同一セッションに実装ログが残っていれば手戻り・訂正を抽出。
別セッション起動で空ならスキップし、「会話履歴は取得できなかった」と明示(欠落を隠さない)。

## Step 3 — 仕分け判定(.agents/rules/common.md 11 章準拠、最終反映先へ直接ルーティング)

各気づきを次の5分類に振り分ける。11章の「バッファ→昇格」モデルと二重化しないよう、
**最終反映先へ直接**振り分ける(全部を agent-lessons バッファに通さない)。

| 分類 | 反映先 | 判定基準 |
| -------------------------------- | ------------------------------- | ------------------------------------------- |
| (a) 再発防止に値する共通規約 | `.agents/rules/common.md` | 全エージェント・全開発に適用される |
| (b) Claude 固有の運用改善 | `CLAUDE.md` / `.claude/rules/*` | Claude Code の harness 挙動・権限に紐づく |
| (c) 手順が複雑・再利用性が高い | 新規 skill 化提案 | 3ステップ以上の定型手順、覚えにくいフラグ群 |
| (d) 特定ツール紐付きの実装メモ | `docs/agent-lessons.md` 追記 | 個別コンポーネントのリスク・実装知見 |
| (e) 一度限りの TIP/既に強制済み | 破棄 | コード・Hook・lint で既に担保 |

## Step 4 — 提案の提示(ここで必ず停止)

仕分け結果を表で提示する(各行: 気づき / 分類 / 反映先ファイル / 変更概要)。
**(e) 破棄も含めて判定理由を明示**する。ここで停止し、ユーザーが承認/却下を選ぶ。
判定に迷うものは (e) 側(破棄)に倒し、過剰提案を避ける。

## Step 5 — 承認分のPR作成

承認された変更のみ `chore/retro-<topic>` ブランチ(**origin/develop 起点**を明示)で実装し、
`--base develop` で PR を作成する(.agents/rules/common.md 6 章/`docs/playbooks/pr-creation.md` 準拠)。
本文は必ずファイル経由(`--body-file`)で渡す。
(c) skill 化提案が承認された場合は `writing-skills` スキルに委譲する。

## やらないこと

- マージ検知の自動化(PostToolUse フック等)は第1弾スコープ外。設計上の留保は
`docs/superpowers/specs/2026-07-05-retro-skill-design.md` を参照。
11 changes: 11 additions & 0 deletions .claude/rules/git-and-fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,14 @@
## git 操作

- `git -C <path>` は使わない。既に project dir に居る場合は素の `git` を使う(`git -C` は sandbox 除外パターンに合致せず SSH push が known_hosts 拒否で失敗する)。

## Playwright / E2E の sandbox 制約(macOS ローカルセッション向け)

本節は macOS ローカルの sandbox-exec 環境で確認した制約。web セッション(claude.ai/code)は Chromium pre-install 済みのコンテナで動くため `playwright install` は不要で、`mach_port_rendezvous` の制約も該当しない。

- ブラウザ未インストール環境では `PLAYWRIGHT_BROWSERS_PATH="$PWD/tmp/claude/ms-playwright"`(リポジトリ内の sandbox 書込可能経路)を指定して `npx playwright install chromium chromium-headless-shell` する。デフォルトの `~/Library/Caches` は書込 deny。キャッシュは未追跡のまま残してよい(次セッションで再利用可)。
- `node` スクリプトから `chromium.launch()` を直接呼ぶと `mach_port_rendezvous ... Permission denied (1100)` で起動できない。**test runner(`npm run test:e2e` / `npx playwright test`)経由なら起動できる**。スクリーンショット撮影等の単発ブラウザ操作も、一時 spec + 専用 config(起動済みサーバを `baseURL` 参照、`webServer` なし)を作って runner 経由で実行する(一時 spec はコミットしない)。
- 環境によっては `webServer` 自動起動が `listen EPERM ::1:4321`(IPv6 bind 拒否)で失敗することがある。その場合は `astro preview --host 127.0.0.1` を別途起動して `baseURL` で参照する。
- さらに環境によっては loopback への **connect 自体が全面 deny** される(`astro preview` の起動・listen は成功するのに、node fetch / curl / バックグラウンドタスクからの `127.0.0.1` 接続がすべて EPERM / exit 000)。この状態では上記 workaround を含め **in-session E2E は実行不能**。接続 probe(`curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:<port>/` 等)が 2〜3 回失敗した時点で workaround 探索を打ち切り、「CI を E2E の最終ゲートにする」判断へ切り替えて PR 本文にローカル E2E 未実行の旨と理由を明示する。UI の目視確認は claude-in-chrome(ユーザーの実 Chrome、sandbox 外)で代替できる。

(経緯: PR #746 のセッションで親・サブエージェント計 3 者が同じ制約に別々に遭遇したため記録。loopback connect 全面 deny は PR #749 のセッションで確認し、workaround 試行のラウンドトリップが無駄になったため追記)
12 changes: 2 additions & 10 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"model": "opusplan",
"model": "opus[1m]",
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
},
Expand Down Expand Up @@ -91,7 +91,7 @@
}
},
"permissions": {
"defaultMode": "default",
"defaultMode": "auto",
"allow": [
"Read(./**)",
"Read(~/.claude/**)",
Expand All @@ -106,12 +106,6 @@
"Edit(/tmp/claude/**)",
"Edit(/tmp/claude-[0-9a-f]*/**)",
"Edit(/var/folders/*/*/T/**)",
"Write(./**)",
"Write(/private/tmp/claude/**)",
"Write(/private/tmp/claude-[0-9a-f]*/**)",
"Write(/tmp/claude/**)",
"Write(/tmp/claude-[0-9a-f]*/**)",
"Write(/var/folders/*/*/T/**)",
"WebFetch(domain:ai.google.dev)",
"WebFetch(domain:code.claude.com)",
"WebFetch(domain:docs.anthropic.com)",
Expand Down Expand Up @@ -187,9 +181,7 @@
],
"ask": [
"Edit(**/.claude/{*.json,*.sh,hooks/**,agents/**,skills/**,commands/**,plugins/**})",
"Write(**/.claude/{*.json,*.sh,hooks/**,agents/**,skills/**,commands/**,plugins/**})",
"Edit(./.gemini/**)",
"Write(./.gemini/**)",
"Bash(git push*)",
"Bash(git reset --hard*)",
"Bash(git commit --amend*)",
Expand Down
1 change: 1 addition & 0 deletions .claude/skills/retro
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ conductor/
.claude/tmp/
.claude/*.bak
.tmp/
# sandbox セッションの作業キャッシュ(Playwright browsers 等 → .claude/rules/git-and-fs.md)
/tmp/

# Superpowers extension (Visual brainstorming artifacts and session info)
.superpowers/
Expand Down
Loading
Loading