fdk-uat について
fdk-uat は、フレームワークの保守担当者向けのリリース受け入れテストスキルです。実際のリモートソースから空のプロジェクトに導入してカナリア検証を行い、続いてメインブランチの既定の導入経路を確認します。失敗した場合はリモートから取り消します。
主な機能
- 01カナリアとメインブランチの二段階検証
- 02空の一時プロジェクトへの導入
- 03新しいリリース機能の検査
- 04CDN センチネルによる反映待ち
- 05失敗したリリースのリモートからの撤回
活用シーン
- 01新機能を含むフレームワークリリースの受け入れ
- 02リモートからの新規導入で必要なファイルが届くか確認
- 03新しいルールが不正な入力を拒否するか検証
- 04UAT 結果やリリース障害の記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rheinmir/ setup --skill fdk-uatインストール後、Claude Code で/fdk-uatを入力して読み込まれたか確認します。
詳細
スキル:fdk-uat
概要
目的とコンテキスト
- 目的: リリース予定のフレームワークを、「初めて
curlで取得するユーザー」の視点で受け入れテストします。空のプロジェクトを作成し、実際のリモート経由で overstack をインストールして、そのバージョンで新たに追加された機能がユーザーの手元で動作するかを、2 つのフェーズ(マージ前の canary、マージ直後の main-URL smoke)で検証します。失敗した場合はリモートから取り除きます。 - トリガー(使用するタイミング):
- 新しい機能(新しい skill、新しい rule、新しい engine)を含むバージョンを公開しようとしている場合。
- 「ドキュメントでは約束されているのに、ユーザーには届かない」(GH#77 クラスの不具合)と疑われる場合。
medic --ciが成功した後。UAT はその上のレイヤーであり、置き換えるものではありません。- ユーザーが「uat」「本番に近いテスト」「downstream のテスト」「初めてインストールする人が実行できるか確認」「acceptance」「/fdk-uat」と言った場合、または新しい機能を含む
/shipの release/pr/mr の場合。
- ユーザーが「uat」「本番に近いテスト」「downstream のテスト」「初めてインストールする人が実行できるか確認」「acceptance」「/fdk-uat」と言った場合、または新しい機能を含む
- 対象外:
medic --ciの置き換え(UAT はその上のレイヤーです)、fresh-install-smoke --local(working-tree のfile://)の代替、実際の LLM モデルを使った live-run(意図的に対象外とし、受け入れ確認は手動で行います)、発見した不具合の修正(取り除いて problem-tree に記録します)。
背景 — 解決する問題(原文のまま):
medic --ci と fresh-install-smoke --local は、working-tree から file:// 経由でインストールします。これらで確認できるのは「自分のマシンにあるコードが正常である」ことであり、「初めて curl で取得した人が実行できる」ことではありません。この 2 つは別のことです。tarball にファイルが含まれていない、.gitignore が出荷すべきものを除外している、frontmatter が壊れた skill を CLI が黙って無視する、global engine が更新されない — こうした問題はすべて、実際のリモート経由でのみ明らかになります。
リモート経由のテストができるのはpush の後ですが、メインブランチへの push である必要はありません。一時ブランチにも raw URL があります。install.sh がデフォルトではメインブランチから skill を取得するため、ソース変数を3 つすべて上書きするという条件のもとで、鶏と卵のパラドックスは解消されます。
ただし、canary だけでは不十分です。別の ref と上書き変数を使って実行するため、まさにデフォルト値(ハードコードされたブランチ名の文字列が含まれる場所)が検証できません。そのためフェーズ 2 が必要です。初めて使う人が入力するそのままのコマンドを、何も上書きせずに実行します。
メンタルモデル
medic --ci 成功 → 新しい機能のチェックリストを宣言(各項目 = 1 つのコマンド)→ フェーズ 1:push HEAD:uat/<ts> → 空のプロジェクトで raw canary から curl(HARNESS_BASE + REPO_RAW + SKILLS_REF)→ UAT チェックリスト + 実際の Orca workspace(assert)→ フェーズ 2:メインブランチを push → sentinel CDN を待機 → README のコマンドを上書きなしで実行 → smoke → PASS を確定 | FAIL なら取り消し(revert/reset --force-with-lease)+ problem-tree。canary は内容を検証し、main-URL smoke はデフォルト値を検証します。
入力と出力の契約
| フィールド | 必須? | 意味 | |
|---|---|---|---|
| In | フレームワークの repo、medic --ci 成功、git がクリーン | はい | ステップ 0 の前提条件です。失敗している場合は push しません |
| In | <owner>/<repo> + メインブランチ | はい | RAW + SKILLS_REF を構築します |
| In | 新しい機能のチェックリスト | はい | push の前に作成します。コマンドとして宣言できない項目は対象になりません |
| In | push の承認(canary / メインブランチ) | はい | push はリモートへの副作用を伴います |
| In | --keep | いいえ | UAT プロジェクトを保持して調査できるようにします |
| Out | BASE + push 予定の commit 一覧 | はい | 失敗時に取り消すための基準点です |
| Out | 各 UAT 項目の結果(実測値) | はい | 3 つの柱 · test-broad PASS · 新しい機能 · orchestration-ready · worktree Orca assert · dot レイアウト |
| Out | 判定 | はい | PASS → wiki/log.md に記録。FAIL → commit をリモートから取り消し、llmwiki/html/fdk-problem-tree.html に status: open のノードを追加 |
| Out | canary ブランチ | — | どちらの終了経路でも削除済み |
ルールと機能
- RULE-01 (MUST): メインブランチにカナリア未通過の変更を絶対に入れません。 フェーズ 1 はこれを実現するためにあります。
- RULE-02 (MUST): カナリアで main-URL スモークテストを代替することはできません。 別の ref と上書き変数を使って実行するため、デフォルト値が見えなくなります。そして、ハードコードされたブランチ名があるのはまさにそのデフォルト値です。フェーズ 2 を省略することは、実際のユーザーが触れるものを検証しないということです。
- RULE-03 (MUST): プッシュしたまま放置してはいけません。 UAT のためにプッシュしたら、同じセッション内で UAT を実行してください。プッシュしてから寝るのは、未検収のビルドを他の人が取得できる状態にしておくことです。
- RULE-04 (MUST): カナリアブランチは、合格時と不合格時の両方で削除します。 ステップ 0 では
git branch -r | grep uat/を一覧表示し、途中で終了したセッションの残骸を削除します。 - RULE-05 (MUST): CDN の反映にはばらつきがあります。直後に測定せず、センチネルを待ってください。
raw.githubusercontentは、同じインストール中にファイル A は新しく、ファイル B は古いまま返すことがあります。その結果、混在したビルドになり、ゲートが誤って赤(あるいは、さらに危険な誤って緑)を示す可能性があります。新しいビルドにしか存在しない文字列をポーリングし、raw が正しい値を返してから測定してください。実測例(2026-07-14):新しいエンジン+古いポリシー → test-broad は 72/74、新しいルールは機能せず。数分待って再実行 → 74/74。 - RULE-06 (MUST): スキルやルールの数を記憶で数えないでください。 インストールしたプロジェクトで LIVE に数えてください。リポジトリ上の数は、ユーザーに届く数ではありません(実際に問題が発生:ドキュメントではスキル 74 個と報告されていたが、インストーラーが届けたのは 67 個 — frontmatter が壊れたスキル 7 個を CLI が黙って無視)。
- RULE-07 (MUST): 新しいルールは存在するだけでなく、実際に効かなければなりません。
policy.yamlにルールの記述があること ≠ ルールによって処理が阻止されること。必ず実際の BAD ファイルでテストしてください。 - RULE-08 (MUST): 意図的な上限(ceiling): ヘッドレス UAT では LLM モデルを起動できないため、「
/orchestrationが動作する」の確認は決定論的な範囲(完全にインストールされている+到達可能+ランタイムへの ping)に限られます。実際のモデルを使ったライブ実行は、引き続き手動での受け入れ確認となります。 - RULE-09 (MUST): 失敗したら削除し、「あとで直すために置いておく」ことはしません。リモートにあるものは、他の人が取得できます。
- RULE-10 (MUST): 実際の Orca ワークスペースは必須です。名前を検証する assert も必要で、「目視で確認できるなら任意」ではありません。 以前は任意と記載されていたため急いで実行する際に省略され、2026-07-21 と 2026-07-24 の 2 回、再度指摘されました。filesystem のみのテストは、他のすべての CLI コマンドが成功しても、完全な UAT とは見なされません。
- 機能:ローカルゲートの実行、リモートブランチのプッシュ/削除とメインブランチの revert/reset(リモートへの書き込み権限が必要)、raw CDN からのダウンロード、一時プロジェクトの作成と Orca への repo/worktree の登録、wiki ログと problem-tree の記録。
失敗時の境界
medic --ciが赤/git が汚れている → ステップ 0 で blocked。プッシュしません。- 新しい機能をコマンドとして提示できない → clarify:それは実行を伴わない約束であり、対象として認めません。
- フェーズ 1 FAIL → failed。カナリアを削除します。メインブランチは汚れません。
- Orca の worktree に名前が表示されるという assert が失敗 → 一時 failed:停止して PASS と報告せず、
worktree createを修正して再検証します。 - CDN センチネルが 30 回試しても新しくならない → まだ測定しません(赤とも緑とも判定しません)。先にローカルファイルで MARK を grep-verify します。
- フェーズ 2 FAIL → failed。直ちにコミットを取り消し(ステップ 5)、problem-tree に記録します。
HOW
メインワークフロー
| ステップ | 種別 | 入力 | アクション | 出力/終了条件 | 失敗時/次の処理 |
|---|---|---|---|---|---|
| W01 | 決定論的 | repo | ステップ 0 — 前提条件:medic --ci、git status --short、git log origin/<nhánh>..HEAD を実行し、BASE を記録する | BASE の基準点 | 赤/汚れあり → ブロック |
| W02 | 判断 | diff | ステップ 1 — 新しい能力のチェックリストを列挙する。各行にコマンドを 1 つ記載する | チェックリスト | コマンドにできない項目 → その行を削除 |
| W03 | 副作用あり | HEAD | ステップ 2 — フェーズ 1:HEAD:uat/<ts> を push し、空のプロジェクトを構築して、3 つすべての変数を指定して raw canary から curl する | UAT プロジェクト | SKILLS_REF がない = 幻の UAT |
| W04 | 決定論的 | UAT プロジェクト | ステップ 3 — チェックリストを実行する(3 本柱、test-broad、新しい能力、オーケストレーション、Orca ワークスペース + assert、ドットレイアウト) | PASS/FAIL | FAIL → canary を削除して停止(B01) |
| W05 | 副作用あり | フェーズ 1 の PASS | ステップ 4 — フェーズ 2:メインブランチを push し、canary を削除して CDN sentinel を待ち、README のコマンドを override せずにそのまま実行し、約 1 分のスモークテストを行う | PASS/FAIL | FAIL → W06 |
| W06 | 副作用あり | フェーズ 2 の FAIL | ステップ 5 — commit を取り消す(revert または --force-with-lease による reset)+ problem-tree を記録する(B02) | リモートがクリーン | — |
| W07 | 副作用あり | PASS | ステップ 6 — 完了処理:UAT プロジェクトをクリーンアップする(または --keep を指定する)。測定値を wiki/log.md に記録する | 検収済みの版 | — |
各ステップの詳細(W01–W07 の信頼できる情報源):
0. 前提条件 — 省略禁止
python3 fdk/tools/medic.py --ci # PHẢI xanh. Đỏ mà vẫn push là cố ý đẩy rác lên remote.
git status --short # sạch (không untracked lạc)
git log --oneline origin/<nhánh>..HEAD # in ĐÚNG những commit sắp đẩy — ghi lại, đây là thứ sẽ gỡ nếu fail
BASE=$(git rev-parse origin/<nhánh>) を記録する — 戻るための基準点です。
1. 今回の版の新しい能力を列挙する(UAT チェックリスト)
push する前に、今回の版で新たに何ができると約束するのかを具体的に書き出します。各項目はコマンドで検証できなければなりません。
- 新しい Skill → インストール後に
~/.claude/skills/<tên>/SKILL.mdが存在し、新しいプロジェクトのCAPABILITIES.mdに記載されていること。 - 新しい Rule → 新しいプロジェクトで実際に機能すること(BAD ファイルを書くとブロックされ、GOOD ファイルなら通る)。
- 新しい Engine/tool → グローバルハーネスのホームから到達できること。
コマンドで検証できる形にできなければ、能力とは見なしません — それは空約束です。
2. フェーズ 1 — CANARY ブランチ(メインブランチには何も反映されません)
リモートの URL は push 後に初めて存在します — ただし、メインブランチに push する必要はありません。一時ブランチにも raw URL があり、curl はどのブランチかを気にしません。
CANARY="uat/$(date +%y%m%d-%H%M)"
git push origin HEAD:"$CANARY"
空のプロジェクトを構築し、canary ブランチそのものの raw からインストールします — 3 つすべての変数を指定してください。そうしないと、黙ってメインブランチの内容が取得されます。
D=~/orca/overstack-uat-$(date +%y%m%d-%H%M)
mkdir -p "$D" && cd "$D" && git init
RAW="https://raw.githubusercontent.com/<owner>/<repo>/$CANARY"
curl -fsSL "$RAW/harness/poc-vendor-neutral/bootstrap.sh" \
| HARNESS_BASE="$RAW/harness/poc-vendor-neutral" \
REPO_RAW="$RAW" \
SKILLS_REF="<owner>/<repo>#$CANARY" \
bash
git add -A && git commit -m "fresh overstack install" # Orca cần ≥1 commit mới nhận repo
SKILLS_REFがない場合、UAT は幻になります。install.shはデフォルトで<repo>#<nhánh chính>から Skill をインストールします — そのため、override しないと canary はメインブランチの Skillをインストールします。つまり、古い版を評価して新しい版に PASS を出すことになります。嘘をつくゲートが緑のままなのは、ゲートがないよりも悪いことです。
ステップ 3 のチェックリストを実行します。PASS → フェーズ 2 に進みます。FAIL → canary を削除します。メインブランチは一切汚れていません:
git push origin --delete "$CANARY"
3. UAT — 実際のプロジェクトで手順 1 のチェックリストを実行する
最低限、fdk/docs/fresh-install-gate.md に従って、以下を確認します。
- 3 つの柱が揃っていること:
.harness/poc-vendor-neutral/policy.yaml·.claude/settings.json·.pre-commit-config.yaml·.llmwiki/wiki/index.md·CAPABILITIES.md。 - Harness が実際に動作すること:
bash .harness/poc-vendor-neutral/test-broad.sh→ PASS(validator GOOD-pass / BAD-block)。 - 新しい機能が届いていること — 今回のリリース固有の項目(手順 1 のチェックリスト)。最も省略されがちな項目であり、新しいリリースに価値があることを証明する唯一の項目です。
- Orchestration 対応済みであること: スキル
orchestration/orca-cli/orca-dispatch-referenceにアクセスできること。 - 独立したリポジトリモジュールが使えること(orca-graph): 空のプロジェクト HOME で
python3 ~/.claude/harness/harness/scripts/orca-graph.py --versionを実行し、orca-graph X.Y.Zが出力されること(rc 0)。rc 3 は shim は届いているが engine が届いていない状態です。他のすべてが問題なくても FAIL です。--no-graphでインストールした場合は、逆に rc 3 と正確に 1 つのインストールコマンドが出力されることを期待します。fresh-install-smoke.shの項目 (G) で自動確認し、結果を UAT チェックリストに記録します。 - 必須(任意ではありません — 2026-07-24 のフィードバック。今回で 2 回目の、この手順のスキップに対する指摘):実際の Orca ワークスペースを構築し、アプリに表示されることを自分で確認してください。ファイルシステムレベルのテストだけでは不十分です。 一時ディレクトリに curl でインストールして CLI でテストするだけでは、完全な UAT とはみなされません。ユーザーには何も見えず、「画面に表示されなければ使えない」ということです。これはハードゲートです。この手順を省略した場合、UAT を PASS とみなしてはいけません。
WT_NAME="uat-$(date +%y%m%d-%H%M)" # tên xác định, dùng để verify ở bước sau
REPO_ID=$(orca repo add --path "$D" --json | python3 -c "import json,sys; print(json.load(sys.stdin)['result']['repo']['id'])")
orca worktree create --repo "id:$REPO_ID" --name "$WT_NAME" --setup skip --no-parent --activate --json
実際に起きた落とし穴:
orca repo add <path>の位置引数 →Unknown command。リポジトリに commit がない → Orca が認識しない。repo addではアプリにワークスペースが表示されません —worktree createが必要です。
確認ゲート — 上記のコマンドを実行した直後に実行してください。これは補助的な手順ではありません:
orca worktree list --repo "id:$REPO_ID" --json | python3 -c "
import json, sys
d = json.load(sys.stdin)
names = [w['displayName'] for w in d['result']['worktrees']]
assert '$WT_NAME' in names, f'KHÔNG THẤY worktree tên {\"$WT_NAME\"} — UAT KHÔNG ĐƯỢC TÍNH LÀ PASS. Có: {names}'
print(f'✓ worktree \"$WT_NAME\" hiện thật trong Orca — {names}')
"
ここで Assertion が FAIL になった場合は、停止し、ユーザーへの PASS 報告を続けてはいけません — worktree create コマンドを修正して(通常は --repo の selector 形式が間違っているか、repo add が commit されていないためです)、再度確認してください。これが「毎回忘れずに自分でワークスペースを構築する」ことに代わる構造的なゲートです — 手動での確認は 2 回連続で失敗したため(2026-07-21、2026-07-24)、assert で強制します。
6. 標準の dot レイアウトであること: UAT プロジェクトのルートに llmwiki/ や harness/ がそのまま存在せず、.llmwiki/ · .harness/ のみが存在すること(AP-7 layout hallucination)。
4. フェーズ 2 — merge 直後に main-URL smoke を実行する(canary では代替できません)
フェーズ 1 では別の ref と3 つの override 変数を使うため、まさにデフォルト値が見えません。デフォルト値にはハードコードされたブランチ文字列(bootstrap.sh の BASE=、install.sh の REPO_RAW=、SKILLS_REF=)が含まれています。このフェーズでのみ、新規ユーザーが実際に入力するコマンドそのものを検証できます。
git push origin HEAD:<nhánh chính> # merge — bản này ĐÃ qua canary
git push origin --delete "$CANARY" # dọn nhánh tạm
測定前に CDN の伝播を待ってください — 必須です。 raw.githubusercontent.com は push 直後に新しいバージョンを配信するとは限らず、遅延はファイルごとに異なります。engine(bin/llmwiki-validate.py)は新しい一方で policy.yaml は古いまま、という状態が実測されています。その結果、インストール内容が新旧混在になり、ゲートが誤って RED と判定します。さらに危険なのは、同じ仕組みによって、古いファイルがたまたまテストを通過することで誤って GREEN と判定される可能性もあることです。
sentinel で確認します — raw が push したばかりの内容を返すまで poll します。
RAW="https://raw.githubusercontent.com/<owner>/<repo>/<nhánh chính>"
MARK="<một chuỗi CHỈ có ở bản mới>" # vd tên rule/field vừa thêm
# ⚠ GREP-VERIFY MARK trên file bản mới TRƯỚC (grep "$MARK" <file local>) — chọn pattern đoán
# mà không khớp file → vòng lặp chờ hết lượt rồi tưởng raw còn cũ, dù raw ĐÃ mới (p-32).
for i in $(seq 1 30); do
curl -fsSL "$RAW/harness/poc-vendor-neutral/policy.yaml" | grep -q "$MARK" && break
echo " raw còn cũ, chờ CDN… ($i)"; sleep 10
done
その後、README に記載されたコマンドをそのまま実行します — 変数の override は一切しません:
D2=$(mktemp -d) && cd "$D2" && git init -q
curl -fsSL "$RAW/harness/poc-vendor-neutral/bootstrap.sh" | bash
短縮版(約 1 分):3 つの柱が揃っていること · bash .harness/poc-vendor-neutral/test-broad.sh が PASS すること · 新しいスキルに ~/.claude/skills/ からアクセスできること。
FAIL → 直ちに取り消します(手順 5)。メインブランチのリスク期間を「長い UAT 全体」から「約 1 分の smoke 1 回」に短縮します。
5. PASS でない場合 → リモートから commit を直ちに取り消す
フェーズ 2 が RED になった場合(または誰かが canary を省略して直接 push してしまった場合)にのみ使用します。状況に応じて選択してください:
# (a) Nhánh chia sẻ / đã có người kéo → REVERT (không viết lại lịch sử):
git revert --no-edit <sha>..HEAD && git push origin <nhánh>
# (b) Nhánh chỉ mình dùng, vừa đẩy xong, chắc chắn chưa ai kéo → RESET:
git reset --hard "$BASE" && git push --force-with-lease origin <nhánh>
--force ではなく --force-with-lease を使います。その間に誰かが push していた場合、他の人の作業を消すのではなく、コマンドが拒否されます。
取り消し後、失敗した理由を llmwiki/html/fdk-problem-tree.html に記録します(新しい node、status: open)。UAT の失敗はデータであり、恥ずかしいことではありません。
6. PASS → 確定
- UAT プロジェクトを片付けます(または、確認が必要なら
--keepで残します)。 - 実際の測定結果(約束ではなく)を
wiki/log.mdに記録します。 - リモート上の版は「初めてインストールする人」のレベルで受け入れ済みと見なします。
ブランチ
| ID | 種類 | 条件 | 動作 | スキップ/失敗 | 再合流 |
|---|---|---|---|---|---|
| B01 | リカバリー | PHA 1 FAIL | git push origin --delete "$CANARY" を実行します。メインブランチには触れません | — | 終了(失敗) |
| B02 | リカバリー | PHA 2 FAIL(または誤って canary を使わずに直接 push した場合) | 共有ブランチ → git revert --no-edit <sha>..HEAD、まだ誰も取得していない個人ブランチ → git reset --hard "$BASE" + --force-with-lease を実行し、problem-tree ノードを記録します | 決して裸の --force を使わないでください | 終了(失敗) |
| B03 | リカバリー | worktree Orca の assert が FAIL | 停止し、--repo セレクター/repo add 前の commit を修正して、再度検証します | PASS を報告してはいけません | W04 項目 5 |
| B04 | ユーザー任意 | --keep | UAT プロジェクトを片付けずに残し、確認できるようにします | — | W07 |
| B05 | リカバリー | 手順 0 で git branch -r を一覧表示した際に、古い uat/ ブランチが残っている | 途中で終了したセッションの不要な canary を片付けます | — | W01 |
検証と停止
PASS となるのは、手順 3 のチェックリストの全項目がコマンドで緑になり($WT_NAME という名前の worktree の assert も含む)、かつ sentinel 後の PHA 2 の smoke test が緑になった場合のみです。記憶に頼らず、インストールしたばかりのプロジェクトで LIVE の skill/rule の数を数えます。sentinel のポーリングは最大 30 × 10s です。push したまま放置してはいけません。UAT は同じセッション内で実行します。
例
- 成功例:
record-episodeskill を追加した版 → チェックリスト "~/.claude/skills/record-episode/SKILL.mdが存在し、CAPABILITIES.mdに記載されている" →uat/260919-1030に push し、SKILLS_REF="<owner>/<repo>#uat/260919-1030"で curl → test-broad PASS、skill に到達可能、orca worktree listにuat-260919-1030が表示される → メインブランチに push し、sentinel が一致、smoke test で override なしに PASS → canary を削除し、wiki/log.mdに記録します。 - 境界/失敗例: sentinel を待たずに、PHA 2 で push 直後に測定 → 新しい engine + 古い
policy.yaml→ test-broad 72/74、新しいルールが機能しない → これは誤検知です。sentinel を待ってから再測定します(74/74)。sentinel 後も失敗する場合 → revert で commit を取り消し、status: openのノードを記録します。
出典
fdk/docs/fresh-install-gate.md(§「標準フロー:新しい Orca workspace を構築して fresh-install をテストする」)から抽出したフローと、2026-07-14 のユーザー要件:先に push して実際にテストできるようにし、PASS しなければリモートから commit を取り消します。- 二段階方式は、同日、ユーザーが「それなら main の curl が正しいかをテストできるのか?」と異議を唱えた結果です。できません。canary で証明できるのはリモート経由で 内容 をインストールできることだけで、デフォルトのコマンド が動作することを証明できるのは main-URL smoke test だけです。また、
install.shが#orcaをハードコードしていて override する方法がないことも判明しました。これがなければ、canary は誤って古い版を判定してしまいます。