仕様を変えないアプリケーションリプレイスで、共通 UI 部品を画面より先に作るときに、現行アプリから部品の見た目の基準を採り、実装し、部品カタログ上で照合する replace-strategy の姉妹スキル。採取の単位は部品インスタンス(部品 × ページ)で、要素単位のスクリーンショット・状態別の計算後スタイル・当たっている CSS 規則・データ依存部品の実データを採る。インスタンス間で値が割れた軸を可変(引数)、割れない軸を固定として決定論的に割り出し、実装後はカタログを同条件で採って parity-suite 同梱の差分ツールで照合する。1 回で 1 部品。replace-strategy setup と .replace/components.md が前提で、未整備なら停止する。「共通部品の見た目の基準を採って」「部品を先に作る」「parity-component」や capture / build を伴う依頼で発動する。
Resources
4Install
npx skillscat add shoji9x9/skills/parity-component Install via the SkillsCat registry.
Parity Component
replace-strategy の姉妹スキル。共通 UI 部品を画面より先に作るときに、その実装の正解になる「現行の部品の見た目」を採り、実装し、部品カタログ上で照合するところまでを受け持つ。
機能(画面)単位の工程は、ページが 1 枚できてから動く。工程は parity-suite の採取、parity-replace の実装、parity-diff の差分である。
部品を先に作ると、その時点では対象のページが無いので、採取する対象も比較する対象も無い。
足りないのはそこだけなので、このスキルは部品の分だけを埋め、機能単位の工程には触らない。
使い方
parity-component capture [--component <slug>] [--target <name>] [--autonomous]
parity-component build [--component <slug>] [--target <name>] [--autonomous]| モード | 対象環境 | 内容 |
|---|---|---|
capture |
side: current |
.replace/components.md が挙げた部品インスタンス(部品 × ページ)ごとに、要素単位で見た目の基準を採る。採ったインスタンスを突き合わせて、固定軸と可変軸を割り出す |
build |
side: new |
割り出した軸から引数を設計して部品を実装する。カタログに状態ごとの見本を置き、同じ条件で採って照合し、差分がゼロになるまで往復する |
- 1 回の実行で扱うのは 1 部品である。複数の部品を並行して進めない(採取・設計・照合が浅くなる)。
--autonomousは、その実行だけを自律で進めるという宣言である(下の「自律実行」)。省略したときは、判断のたびに確認する。slugは.replace/components.mdが採番したものを使い、自分で採番しない。省略したときは、まだ着手していない部品から対話で選ぶ。--target <name>の選び方は、replace-strategyのreferences/project-config.md「実行対象環境」の「選択規則」に従う(ここへ転記しない)。captureはside: currentだけを、buildはside: newだけを候補にする。- 自然文でも発動する。例は「共通部品の見た目の基準を採って」「部品を先に作りたい」「この部品を現行と突き合わせて」である。
前提
- ツール:
gitと Node.js(Playwright の実行環境)。buildにはgh(GitHub CLI)も要る。手順 1 でissue-startに任せてブランチを作り、手順 8 で部品の Issue を再取得して受け入れ条件を突き合わせるためである。captureは Issue を操作しないので要らない。 - 前提スキル:
replace-strategy(setupが完了していること)、golden-dataset(フェーズ A が完了していること)、parity-suite。parity-suiteは、同梱の差分ツールと、撮影条件を定義した原本を読むために使う。対象の slug でparity-suiteを実行しておく必要は無い。buildでは、issue-start(ブランチの作成と受け入れ条件の突き合わせを任せる先。--branch-onlyと--acceptanceで呼ぶ)と、parity-replace(敵対的レビューの手順の原本)も使う。 - 前提スキルがインストールされていなければ、
gh skill install shoji9x9/skills <name>で入れてから実行する。
設定スキーマ・差分ツール・撮影条件の原本はreplace-strategyとparity-suiteにあるので、このスキルだけでは動かない。 - MCP: 要らない。現行アプリとカタログは Playwright 自身が操作する。
- Playwright(TypeScript)を前提にする。
parity-suiteの撮影条件の規約・差分ツール・特性採取ツールをそのまま当てるためで、別のランナーでは同じ条件を再現できない。Playwright を使えないプロジェクトでは停止する。
ノイズ基準値は、parity-suiteの実行を待たずにcaptureの中で自分で測る(`references/capture.md`「ノイズ基準値」)。
機能単位のparity-suiteは部品より後に実行されるので、その結果を前提にすると部品を先に作れなくなる。 - 部品カタログが要る(
buildだけ)。実体は問わないが、取り決めを満たしていること。取り決めと設定の解決は `references/catalog.md` にある。 - 前提を次のように判定する。無ければ停止し、該当するスキルの実行を促す。無いものを作り出さない。
replace-strategy setupの完了は、設定.config/skills/shoji9x9/skills.ymlのskills.replace-strategyと.replace/features.mdが在ることで判定する。- 部品インベントリは、
.replace/components.mdが在り、対象の slug の行にインスタンスが 2 つ以上挙がっていることで判定する(`references/instances.md`)。 golden-datasetのフェーズ A の完了は、.replace/dataset/metadata.jsonが在ることで判定する。- setup とフェーズ A は、まだ解決していない保留があれば、証拠があっても完了していないものとして扱う。どの保留を見るかは、
replace-strategyのreferences/autonomy.md「下流の前提判定」で定義する。 buildの前提は、対象の slug のcaptureが完了していること(.replace/components/<slug>/metadata.jsonのcapture.complete)と、axes.okが真であることの両方である。capture.completeだけでは足りない。全インスタンス × 全状態を採っていても、id の重複・採っていない状態・片側でしか採れていない軸が残っていれば、axis-diff.mjsはok: falseを返す。
そのときのcomponent-api.mdは実装の根拠にならないので、採取へ戻る。metadata.jsonの宣言だけで通さない。下の「比較の母集合」のすべての組み合わせについて、採取で必須の成果物がすべて揃っていることを確かめる。baseline/<instance>/<state>/には、要素のスクリーンショット(element.png)・撮影の記録(element.shot.json)・特性(traits.json)・当たっている CSS 規則(css-rules.json)の 4 点が要る。
slug の直下にはaxes.jsonとcomponent-api.mdが要る。ファイル名まで固定するのは、名前を決めないと前提を機械的に判定できず、在るはずのものを人が目で探すことになるからである。- データ依存の部品(
.replace/components.mdでデータ依存: true)は、baseline/<instance>/data.jsonも必須である。 - 操作の結果の
baseline/<instance>/behaviors.jsonも、全インスタンスで必須である。ただし、capture.operations_none_reasonで操作の無い部品と宣言した場合は除く。
この時点では突き合わせ表がまだ無いので、behavior-compare.mjsはcomparison-missingで必ず exit 1 になる。
そのため終了コードでは判定せず、ほかの finding(behavior-baseline-*・unreachable-declaration-invalid)が 0 件であることで判定する。残っていれば、buildの前にcaptureへ戻す。 - 動きの時系列の
baseline/<instance>/motions.jsonも、全インスタンスで必須である。ただし、capture.motions.none_reasonで動きの無い部品と宣言した場合は除く。capture.motions自体が無ければ、motion-compare.mjsが形式の誤り(exit 2)で失敗するので、動きを数えていない部品はcaptureへ戻す。
判定は操作の結果と同じく、comparison-missing以外の finding が 0 件であることで行う。
対象の finding はmotion-baseline-*・motion-noise-missing・現行側のmotion-timeline-invalidとmotion-probe-version-mismatch・unreachable-declaration-invalidである。 - 一部だけ揃った採取を通すと、画素比較の入力やカタログに入れるデータが無いまま
buildに入る。
宣言は古い実行の残りの場合もあるので、実体を見ずに通すと、比較の対象が空のままbuildに入る。
- 比較の母集合: 採取・前提の判定・見本・照合・完了判定は、すべて次の 1 つの定義を使う。
母集合は、instances[]×capture.statesの組み合わせから、そのインスタンスのunreachable_statesに宣言された状態を除いたものである。
除くかどうかの根拠は宣言である。metadata.jsonのinstances[].unreachable_statesに状態名と理由があり、同じ内容がgaps.mdにも残っていることを確かめる(`references/instances.md`)。
宣言の無い欠けは除かない。採り忘れと区別できないので、母集合に含めたまま実体が無いものとして扱い、採取へ戻る。capture.completeも、全インスタンス × 全状態ではなく、この母集合に対して判定する。宣言済みの到達できない組み合わせは数えない。 - 軸の割り出しの対象は、母集合より狭い。全インスタンスで到達できる状態だけが対象になる。
あるインスタンスで作れない状態は、突き合わせる相手が居ないので、固定とも可変とも言えない。axis-diff.mjsは、マニフェストのinstances[].unreachable_statesに宣言された欠けを除外として扱い、対象から外した組み合わせをnot_comparedに残す(宣言の無い欠けは問題にする)。
外れるのは「そのインスタンス × その状態」の組み合わせだけで、照合の母集合からも同じ単位で外れる。
到達できない状態はそのインスタンスで採れないので基準が無く、見本も作らない(`references/catalog.md`)。
同じ状態でも、到達できる別のインスタンスは母集合に残り、そのインスタンスの見本は作る。
状態ごと落とすと、採れている基準が照合されないまま消える。外した事実と理由はgaps.mdに残し、完了報告でも収束と並べて示す。
厳守の制約(禁止事項)
- 採取していない状態とインスタンスを、実装の根拠にしない。
「ボタンなら hover と disabled があるはず」は、採取する対象を挙げる材料であって、正解ではない。
正解は動いている現行アプリである(parity-suiteのreferences/coverage.md「状態網羅の導出源」と同じ考え方)。 - 1 つのインスタンスで測った値を、部品の値として固定しない。固定と可変は、2 つ以上のインスタンスを突き合わせないと区別できない。
インスタンスが 1 つしか無い部品は、共通部品として先に作る対象にしない(その機能を実装するときにparity-replaceが作る)。 - 計算後スタイルだけで実装しない。計算値は「今の状態の結果」なので、
:hoverの宣言も!importantの勝ち負けも見えない。
当たっている CSS 規則も併せて採る(`references/capture.md`)。 - 採取ツールが「読めなかった」と報告した箇所を、無かったことにしない。
inaccessible(クロスオリジンのスタイルシート)とunresolved(判定できないセレクタ)が 0 でなければ、gaps.mdに残す。0 件を「差が無い」の根拠にしない。 component-coverage.json(parity-suiteの部品の網羅表)を、見た目の根拠にしない。
この表は操作と状態の有無を数える表で、色・寸法・余白は見ていない。機能が揃っていて見た目が全部違う部品も、presentで埋まる。- 見た目の照合を、操作の結果の根拠にしない。状態ごとの見た目が全部一致していても、操作した結果(全選択になる・チェックが残る・書き出しで失敗する)は別の測定である。
操作の結果を示すのは、behavior-compare.mjsの突き合わせだけである。 - 「アニメーションは対象外」として、部品の動きを済ませない。見た目の照合は動きを止めて撮るので、動きの有無も長さも示さない。
部品ごとに動きを数え、時系列をmotion-compare.mjsで突き合わせる(`references/motion.md`)。
同じように、毎回同じ順で描く照合とスイートは、部品の一生の順番で不具合が出ることを示さない(`references/lifecycle.md`)。 - LLM に「差分があるか」を聞かない。差分の検出は決定論的なツール(画素の比較・特性の照合)が行い、LLM は分類(要対応・許容・環境ノイズ)だけを行う。
「同じに見えます」を収束の根拠にしない。 - 現行アプリには、操作して状態を作る範囲を超えて触らない。正解の基準を変えないため、現行アプリのコードとデータを変更しない。
状態を作る操作は「読み取りだけ」に含まれない。選択した target のforbidden_actionsを先に読み、禁止された操作で作る状態には遷移せず、gaps.mdに残す。 - 現行から抜き出したデータを、出所を確かめずにカタログへ持ち込まない。ゴールデンデータセットから来たと確かめられないデータは使わない(`references/capture.md`「データ依存部品」)。
- カタログ同士や、カタログとベンダーの見本を突き合わせない。比べる相手は、常に現行アプリから採った基準である。
- 意図的差異レジストリに宣言の無い差を、引数のデフォルト値や個別の分岐で吸収しない。宣言に無い差は
intentional_diffs.pendingへ回して、ユーザーに確認する。 - 既存のパッケージを探さずに、自前の実装を始めない。探した結果として自前の実装を選ぶのはよい。そのときは理由を記録する(原本は
replace-strategyのreferences/dependency-selection.md)。 - 部品の Issue の受け入れ条件を、利用者に確認せずに外さない。
確認してから決めるのは、受け入れ条件と違う実装にすることと、受け入れ条件に当たる観点や検証を飛ばすことである。
たとえば、現行に無い振る舞い(フォーカスの閉じ込め・キーボード操作・引数のデフォルト値など)を「現行に合わせる」という理由で外すことが当たる。
飛ばす前に、元に戻す手段を探し、探した結果を判断材料に書く。
コードの注記・gaps.md・parity.mdに「条件を満たさない理由」を書いたら、同じ内容を判断待ちにも積む。注記は「理由を書いた」形になり、照合もレビューもそれ以上を求めないからである。
この取り決めの原本は、replace-strategyのreferences/autonomy.md「受け入れ条件から外れる判断」である。 - 破壊的な変更を自分で決めない。既存の見本の出力が変わる引数の削除や意味の変更は、影響範囲を示してユーザーに判断を求める(`references/amend.md`)。
- シークレットの値を、コード・ログ・成果物に残さない。環境変数の名前だけを扱い、値は書き写さない。
プロジェクト設定の解決
設定ファイル .config/skills/shoji9x9/skills.yml の skills.replace-strategy.* を直接読む(転記しない)。
スキーマの原本は replace-strategy の references/project-config.md である。このスキルが読み書きするキーは次のとおりである。
| キー | 用途 |
|---|---|
targets |
実行対象環境。capture は side: current、build は side: new の中から --target で選ぶ。pre_commands・start・check_urls があれば、起動と稼働の確認に使う |
targets[].catalog_url / targets[].catalog_url_command |
新側の target の部品カタログの baseURL。build ではどちらか 1 つが必須である。固定の文字列なら catalog_url、実行ごとに変わる環境なら catalog_url_command を使う(url / url_command と同じく、両方は書けず、解決の規則も同じ)。両方あるときも、どちらも無いときも、推測せずに停止してユーザーに確認する(取り決めは `references/catalog.md`) |
targets[].auth.roles / targets[].forbidden_actions |
選択した target の、ロールごとの認証情報(環境変数の名前)と、実施しない操作。capture(現行の target)と build(新側の target のカタログ)の両方で読む。保護されたカタログは、認証しないと見本に到達できないからである。storageState の作り方とロール名の扱いの原本は、parity-suite の references/auth.md である。capture も forbidden_actions を読む。checked・selected・error の状態はクリックや送信でしか作れず、採取自体は読み取りでも、状態を作る操作は書き込みになることがある。禁止された操作で作る状態には遷移せず、gaps.md に残す |
references.component_catalog |
カタログの取り決めを書いた文書のパス。実体(Storybook など)・見本の書き方・データの入れ方・URL の決まり方を書く。整備されていなければ build に入らずに停止し、整備を促す。カタログの実体を、スキルが勝手に決めない |
references.ui_library |
新しい UI ライブラリの設定と、旧→新の design token の対応表。整備されていなければ、build の手順 5(テーマ寄せ)に入らずに停止する。源流で系統差を縮められず、宣言と未検証が増えるからである。止める位置は手順 5 の直前で、手順 1 ではない。手順 1〜4(前提の検証・引数の設計・部品の採否・実装)はこのファイルを読まないので、そこで止めると要らない停止になる。手順の原本は parity-replace の references/theming.md である |
references.architecture |
新側のアプリの骨格の決定記録。部品は骨格の上に載るので、整備されていなければ build に入らずに停止する |
references.coding_conventions |
部品と見本を書くときに従う規約。整備されていなくても停止しないが、推測で自分の流儀を持ち込まない。基底ドキュメント・リントの設定・既存のコードから読み取る |
references.dependency_policy |
依存を入れるときの方針。値は 3 つあり、none とキーが無いことを同じに扱わない。キーが無い(まだ確認していない)ときだけ、ユーザーに要否を確認し、その結果を同じキーに追記する(既存の値は消さない) |
new.stack |
新側のスタックの一覧。部品の候補がスタックと両立するかの判断に使う。空かキーが無ければ、推測せずにユーザーに確認し、その結果を同じキーに追記する(既存の値は消さない) |
intentional_diffs.{keep,may_change,pending} |
意図的差異レジストリ。見つけた差は、誰が足したか分かる形で pending に追記し(既存の値は消さない)、ユーザーに確認する。書くキーは 4 つで、差の文言の item(照合のキー)、slug、added_by: parity-component、追記した日の added_at である。slug には cross-cutting を書く。slug は機能の slug の名前空間なので、部品の slug を書くとどの機能の棚卸しでも対象外になり、いつまでも棚卸しされない。item を別のキー名で書くと、追記のときは通り、数工程後の parity-diff の棚卸しで「item が空」として現れる。keep と may_change へ移すのは人である。例外は、静的資産で「同等物を作る」を選んだときの宣言で、ユーザーの承認を得てから may_change に追記する(pending を通さない。原本は replace-strategy の references/static-assets.md) |
component_diffs |
テーマで消せない構造の差を登録する、系統差のレジストリ。宣言の原本は parity-replace(references/theming.md)である。このスキルは、読んで照合の正規化に使うだけで、書くときは同じ手順(ユーザーの確認)を通す |
artifacts.{retention,storage,size_threshold_mb,overrides.<slug>} |
大きなバイナリの保存先のデフォルトと、部品ごとの上書き |
verification_commands |
実装と見本に通す検証コマンド。通すのは full(全体を調べる)である。full キーが無いとき、または verification_commands 自体の値がリスト(実行する範囲を宣言していない古い形)のときは、build の完了を判定できないので停止する。full の値がコマンドのリストなのは新しい形で、正常である(full と diff の 2 列に分かれていれば移行済み。見分け方の原本は、スキーマの文書の「verification_commands の形の変更」) |
parity_suite_dir |
パリティスイートの置き場所(指定が無ければ e2e/)。差分ツールのコピー先と、カタログを採るスペックの置き場所の起点にする |
secrets.wrapper |
シークレットが要るコマンドの前に付けるラッパー |
- 古いキーを代わりに読まない。スキーマの原本の「移行」の節に挙がった古いキーを見つけたら、同じ節の対応表を示して停止する。
自律実行(--autonomous)
自律実行の規約(宣言・越えない線・停止の 2 分類・保留の記録の形・最後にまとめて聞く手順)の原本は、replace-strategy の references/autonomy.md である(ここへ転記しない)。
このファイルを読めないときは自律実行せず、確認のたびに止まる。このスキルに固有の扱いは次のとおりである。
- 対象の選択(
--componentを省いたときと、デフォルトの無い--target)は保留にせず、候補を示して停止する。記録先が slug と target で決まるためである(原本の「宣言」)。 - 判断待ち(保留に積む)にするものは次のとおりである。
- 同梱ツールのコピー先が同梱版と一致しないときの扱い
- インスタンス間で割れているが、区別する理由が見つからない軸(現行の不整合)を揃えるか
- 部品の依存の決定(
new.stackが空のときを含む) - 台帳に無い静的資産の方針
- 部品の Issue の受け入れ条件と違う実装と、受け入れ条件に当たる観点の省略(上の「厳守の制約」)
- 受け入れ条件の突き合わせ(
buildの手順 8)の結果を Issue にコメントし、チェックを付けること(外向きの操作)
- 保留に積んでも進める工程がある。割れた軸の扱いが保留なら、その軸を含まない引数の設計・実装・見本の採取は進め、その軸に依存する見本の照合は行わない。
- 記録先は
pending_decisions[]とrun.autonomousである。
ファイルは、captureなら.replace/components/<slug>/metadata.json、buildなら.replace/components/<slug>/new/<target>/build-metadata.jsonである。
まだ解決していない保留が残る間は、capture.completeをtrueにしない。buildは収束したと報告せず、loop.stopped_reasonに判断待ちを書く。 buildの敵対的レビューの手順(parity-replaceのreferences/adversarial-review.md)で、サブエージェントを起動できないときは「人のレビュアーへ渡す」ことになる。これも判断待ちに積む。
実行フロー(capture)
詳しい手順は、それぞれの reference に任せる。番号の順に進める。
前提を検証し、早めに失敗する。上の「前提」を実測で判定し、欠けていれば、無いものを作り出さずに停止して、該当するスキルの実行を促す。
slugを.replace/components.mdと突き合わせる(無い slug なら停止する。自分で採番しない)。
現行の target を決めて、稼働を確かめる(check_urlsで確かめ、落ちていればpre_commands→startを実行して、もう一度確かめる)。
稼働を確かめたら、次に認証する。選択した target がauth.rolesを持つなら、parity-suiteのreferences/auth.mdに従って、ロールごとのstorageStateを用意し、そのロールで採る。
ここを飛ばすと、保護された画面で論理名が 1 件も解決せず、「部品が無い」と「ログインしていない」を取り違える。
使ったロール名は、metadata.jsonのcapture.auth_rolesとinstances[].auth_roleに記録する。ロール名は、設定と成果物を通して同じ名前を使い、読み替えない。
認証が要るのにできないときは、推測で先へ進まずに停止する。採取の対象を決める。
.replace/components.mdの対象の行から、インスタンス(部品 × ページ)と、各インスタンスの論理名を読む。
インスタンスが 2 件より少ない行と、ページか論理名が空の行は、固定と可変を区別できないので採取に進まない。
足りない分はreplace-strategyの側で埋めるよう、ユーザーに促す。詳しくは `references/instances.md` にある。保存先を検証する。
artifacts(overrides.<slug>を含む)に書き込めるかを撮影の前に確かめ、書き込めなければ早めに失敗する。全部撮ってから保存できないと分かるのを避けるためである。状態を列挙する。採る状態を、部品の規範となる資料と現行の UI から挙げる。
資料は、状態を挙げる材料であって正解ではない(材料の原本は、parity-suiteのreferences/coverage.md「状態網羅の導出源」)。
資料が 1 つにまとめている状態でも、現行が描き分けているなら分けて採る(単一選択と範囲選択・複数選択など。同じ原本の同じ節)。
候補の状態の集合は、全インスタンスで共通にする。片方で採らなかった状態は、「差が無い」ではなく「測っていない」になるからである。
例外は到達できない状態だけである。そのインスタンスで作れない状態は、禁止された遷移を試さずにunreachable_statesに理由と一緒に宣言し、比較の母集合と軸の割り出しの両方から外す(`references/instances.md`)。採取する。先に、
parity-suite同梱の特性採取ツールをプロジェクトの側に用意する(`references/capture.md`「parity-suite同梱ツールの用意」)。用意できなければ停止する。
インスタンス × 状態ごとに、次の 4 点を採る。- 要素単位のスクリーンショット。
parity-suite同梱の element-shot.mjs を使う。locator.screenshot()は外接する整数の矩形に丸めるので使わない。 - 計算後スタイル。
parity-suite同梱の trait-capture.mjs を使う。 - 当たっている CSS 規則。同梱の `scripts/css-rules-capture.mjs` を使う。
- データ依存の部品なら、見えている行の実データ。
撮影条件は
parity-suiteのreferences/baseline.mdに従う。同じ条件で 2 回撮ってノイズ基準値を出す(2 回目の採取物は、基準値を記録したら削除する)。詳しくは `references/capture.md` にある。見た目に加えて、操作の結果も採る。部品の機能表から操作を挙げて
metadata.jsonのcapture.operationsに書く。
インスタンスごとに現行で操作し、観測した結果の状態(画素ではない)をbaseline/<instance>/behaviors.jsonに書く。
見た目の照合は、操作の結果を 1 件も示さない。詳しくは `references/behavior.md` にある。部品に掛かる動きも数えて採る。現行のソースと実機の両方で動きを数え、
capture.motionsに書く。
動きのある遷移は、同梱の motion-probe.mjs で、インスタンスごとに同じ条件で 2 回採り、baseline/<instance>/motions.jsonに書く。2 回の差が揺れで、許容差の根拠になる。
動きの無い部品はnone_reasonを書く。
動きが終わってから始まる処理(フォーカス・タイマー・操作の受け付けの開始)は、操作として挙げる。詳しくは `references/motion.md` にある。- 要素単位のスクリーンショット。
固定軸と可変軸を割り出す。
node <skill>/scripts/axis-diff.mjs --baseline .replace/components/<slug>/ --out .replace/components/<slug>/axes.jsonを、exit 0 になるまで通す。
マニフェストは手で組まない。このスクリプトが、採取物から決定論的に組み立てる。コピーせず、スキルの中のスクリプトをそのまま実行する。
採っていないもの・片側だけのもの・id の重複は問題として報告されるので、採取へ戻して埋める。問題を残したまま「可変軸なし」と結論しない。
詳しくは `references/component-api.md` にある。成果物を記録する。書くものは次の 3 つである。
component-api.md: 固定と可変の割り出しと、引数の候補metadata.json: 撮影条件・ノイズ基準値・ツールの版・データセットの版・capture.completegaps.md: 採れなかった箇所と理由
inaccessibleかunresolvedが 0 でなければ、必ずgaps.mdに残す。
実行フロー(build)
前提を検証して着手する。
captureの完了と、references.architecture・references.component_catalog・verification_commands.fullを実測し、欠けていれば停止する。
採取物が古くなっていないかも、あわせて判定する。宣言だけを見ると、古い基準の上に実装して「一致した」と報告することになる。
判定は 2 段で行う。先に設定の宣言と採取物の実体を全部調べ、欠けがあれば、下の 3 項目(古くなっていないかの判定)に進まずに、見つけた欠けをすべて挙げて停止する。
宣言と実体はプロジェクトの中のファイルを読むだけで決まるが、古くなっていないかの判定はparity-suite同梱ツールなど、外の実体に依存する。
順番を決めないと、外の実体のせいで先に止まった実行が宣言の欠けを報告せず、利用者は直して再実行するたびに別の欠けに当たる。- ツールの版を比べる。
metadata.jsonのcapture.toolsに記録された版と集合を、今使うツールの実際の版と集合と突き合わせる。
版はtraits_version・element_shot_version・css_rules_version・axis_diff_version・motion_probe_version(動きのある部品だけ)で、集合はtraits_property_setである。
違っていれば実装に進まず、captureからやり直す。採取のスキーマが違う基準は、比較の入力にならない。 - 軸を導き直す。
node <skill>/scripts/axis-diff.mjs --baseline .replace/components/<slug>/ --out <一時パス>を実行し、exit 0 で、記録済みのaxes.jsonと一致することを確かめる。metadata.jsonのaxes.okと、axes.jsonが在ることだけでは、採取物が変わった後の古い軸や、手で直した軸がそのまま引数の設計に渡る(出力からは区別できない)。 - データセットの版を比べる(データ依存の部品だけ)。
metadata.jsonのdataset_versionと今の版の間のchanges[].affectsが、その部品の実効参照テーブルと交差するなら、古くなっている。
版の数値が古いだけでは、古くなったと判定しない。無関係なテーブルが変わるたびに、採り直しを強いることになるからである。
導き方の規則と、導けないときに停止する取り決めの原本は、golden-datasetのreferences/versioning.mdである。
選択した新側の target が
auth.rolesを持つなら、カタログに到達する前に、captureと同じやり方でstorageStateを用意する(原本はparity-suiteのreferences/auth.md)。
対象の slug に対応する.replace/components.mdの Issue 列の番号で、issue-start <番号> --branch-onlyを実行してブランチを作る。まだ起票されていなければ停止して、replace-strategy issuesを促す。--branch-onlyは外さない。モードを指定しないissue-startは、ブランチを作った後そのまま実装へ進む取り決めなので、任せると同じ Issue に対して実装が二重に実行される。実装は、このスキルの手順 2 以降が受け持つ。- ツールの版を比べる。
引数を設計する。
component-api.mdの可変軸を引数(props)に、固定軸を実装の定数に割り当てる。状態を表す引数(disabledなど)も、可変軸として扱う。
軸を引数にしないと判断したら、理由を書く。たとえば、インスタンスの差が現行の不整合で、揃えることをユーザーが決めた場合である。その場合はintentional_diffs.pendingへ回す。
詳しくは `references/component-api.md` にある。部品の採否と依存を決める。このフェーズで要る部品を自前で書くか、どのパッケージを使うかを実装に入る前に決める。決めたことは
.replace/dependencies.mdに追記する(既存の行は消さない)。
判断の材料・順番・リポジトリの方針の扱いは、replace-strategyのreferences/dependency-selection.mdに従う。setupで決めた部品は、ここで決め直さない。
台帳は、状態が有効の行だけを読む。取り消し済みは履歴である。同じ部品で有効が 2 行あれば、進まずに確認する。内蔵の行の部品は、単体で実装しない。「採用したもの」列のパッケージに含まれるので、そのパッケージを採ったことを確かめて使う。採らないことになっていたら、決定が覆ったものとして扱い、決め直す。機能固有の行は、このスキルの対象外である(機能を実装するときにparity-replaceが決める)。
決定が覆ったら、古い行の状態を取り消し済みにしてから、新しい行を追記する。値の意味・覆り方・読む側の規則の原本は、replace-strategyのreferences/dependency-selection.md「洗い出しの 6 値」である。
部品が描く静的資産(アイコン・画像・書体)は、.replace/assets.mdの同じ種類で、状態が有効の行に従う(取り消し済みの行は履歴)。部品の中でコピーするかどうかを決めない。
台帳に無ければ、方針を空けた行を追記してユーザーに確認し、決まるまでその資産に依存する実装を進めない。原本はreplace-strategyのreferences/static-assets.mdである。実装し、見本を置く。現行のソースコードと採取物を一次情報として実装し、インスタンス × 状態ごとに見本(story など)を置く。
見本には、採取と同じ状態の集合を持たせる。見本の無い状態は照合されない。
CSS の値を実装に転記する前に、css-rules.jsonのmatchedとinline_declarationsの両方から、実際に勝っている宣言を確定する。
同梱のnode <skill>/scripts/cascade-resolve.mjs --css-rules <path> --state <state> --allを通し、undecidableが残ったら、現行の CSS を直接読んで決める。
インラインの値が!important付きの規則に負ける形と、後に読み込まれるテーマの再宣言が前のものを上書きする形は、目で見ると取り違えやすい。
詳しくは `references/catalog.md`「勝っている宣言を確定してから転記する」にある。
データ依存の部品は、captureが採った実データを見本の入力にする。書き方はreferences.coding_conventionsに従う。詳しくは `references/catalog.md` にある。実装したら、部品の一生の順番で不具合が出る流れの対象かを判定する。対象になるのは、次の 3 つがそろうときである。
- 初期化を 1 度しか通らず、その後の変化を自分で受け直す。
- その流れを、既存の検査が通らない。
- 不具合が出る処理を名指しできる。
対象なら、4 つの実行パスのうち名指しできるものに、順番を強制する見本と検査を置き、
build-metadata.jsonのlifecycleに記録する。
検査は、その流れに入った回数(data-*属性)を先に確かめてから、症状を見る。
この見本は見た目の照合の見本ではないので、catalog.storiesに載せず、parity.unbaselined_storiesにも数えない。詳しくは `references/lifecycle.md` にある。見た目の系統差を源流で縮める。
references.ui_libraryが整備されていない(キーが無い・値が空・パスを解決できない)なら、ここで停止して整備を促す。推測でライブラリを決めない。
整備されていれば、トークンの対応表で、古い design token を新側のテーマに寄せる。
テーマで消せない構造の差の扱い(component_diffsに宣言するか、gaps.mdに書くか)は、parity-replaceのreferences/theming.mdで定義する。敵対的レビューをする。commit の前に、ローカルの commit していない差分をレビューする。実装役とレビュー役を分け、レビュー役には判断の基準(差分・現行のコード・採取物・規約・レジストリ)だけを渡す。
手順の原本は、parity-replaceのreferences/adversarial-review.mdである。サブエージェントを起動できないことを、レビューを省く理由にしない。差分だけを人のレビュアーへ渡す方法に切り替える。カタログを採って照合する。カタログを現行と同じ条件で採り、
parity-suite同梱の差分ツール(画素の比較・特性の照合)で基準と突き合わせる。
差分は決定論的なツールが出し、LLM は 1 件ずつ分類(要対応・許容・環境ノイズ)する。要対応は手順 4 へ戻す。詳しくは `references/compare.md` にある。操作の結果も突き合わせる。
captureと同じ操作を、見本で同じ手順で行い、new/<target>/behavior-comparison.jsonに書く。
次にnode <skill>/scripts/behavior-compare.mjs --baseline .replace/components/<slug>/ --comparison <その表> --target <target>を通す。
一致しないものは要対応として手順 4 へ戻す。現行の挙動を引き継がないと判断するなら、利用者に上げる。詳しくは `references/behavior.md` にある。動きも突き合わせる。
captureと同じ遷移を、見本で同じ版のプローブで採り、new/<target>/motion-comparison.jsonに書く。
次にnode <skill>/scripts/motion-compare.mjs --baseline .replace/components/<slug>/ --comparison <その表> --target <target>を通す。
一致しないものは要対応として手順 4 へ戻す。動きを引き継がないと判断するなら、利用者に上げる。詳しくは `references/motion.md` にある。完了を判定する。次のすべてを満たしたら完了である。
説明できない差分が 0 件である。要対応が 0 件で、許容は全件が
intentional_diffsかcomponent_diffsの宣言に結び付いている。verification_commands.fullが通る。比較の母集合(上の「前提」)のすべての組み合わせに対応する見本があり、全件を照合した。
母集合に対応しない見本(基準の無い見本)が 0 件である(`references/catalog.md`「現行に無い見た目を見本に作らない」)。
behavior-compare.mjsが exit 0 である(操作の結果に、突き合わせていないものと一致しないものが 0 件)。motion-compare.mjsが exit 0 である(動きに、突き合わせていないものと一致しないものが 0 件)。一生の順番で不具合が出る流れの対象なら、次のすべてを満たす。
lifecycle.paths[]の全件で検査が通る。- 各検査が、症状より先に、その流れに入ったこと(回数が 1 以上)を確かめている。
- 直した処理を外すと検査が失敗することを確かめてある。
- 順番の見本を、
catalog.storiesにもunbaselined_storiesにも入れていない。
記録は、
node <skill>/scripts/lifecycle-check.mjs --build-metadata <build-metadata.json>が exit 0 になることで確かめる。
このスクリプトは、4 つの実行パスの振り分けの抜けと重複も報告する。対象でない部品にも実行する(`references/lifecycle.md`「完了判定」)。部品の Issue の受け入れ条件の突き合わせが exit 0 である。
受け入れ条件の突き合わせが要るのは、上のほかの判定がどれも採取物との照合で、部品の Issue にだけ書かれた条件(フォーカスの閉じ込め・キーボード操作・引数のデフォルト値など)を数えないからである。
手順 1 で使った.replace/components.mdの Issue 列の番号で、次のコマンドを実行する。issue-start <番号> --acceptance --out .replace/components/<slug>/new/<target>/acceptance.json --decisions .replace/components/<slug>/new/<target>/build-metadata.json- 渡す前に、
build-metadata.jsonのverificationとpending_decisionsを確定して commit する。commit していない変更が残ると、表が根拠の版を固定できない。 - 検査の結果は、後から同じファイルの
acceptanceに書く。loop.stopped_reasonもこのときに書き、次の commit に含める。検査の前に「収束」と書かない。 - 表を作り直すときは、
commitをその時点の HEAD にする。手順と表の様式の原本は、issue-startのreferences/acceptance.mdである。 --allow-laterは渡さない。部品の Issue の条件は、すべてこのスキルの完了で満たす条件だからである(replace-strategyのreferences/features-issues.md「共通部品 Issue」)。
後の工程のparity-diffは画面の収束を見る工程なので、部品の条件を引き受けない(下の「姉妹スキルとの連携」の「parity-diffとの関係」)。後の工程へ回すと、どの工程も数えないまま Issue が閉じる。- 満たせない条件は自分で外さず、判断待ちに積み(上の「厳守の制約」)、その行を
pending-decisionにする。 - 番号を機能の行と共有していて、機能の条件が表に入るときは、
laterに回さず、停止して利用者に確認する。
行と Issue は 1 対 1 であることが前提である。原本は、replace-strategyのreferences/features-issues.md「起票の後に行と受け入れ条件を突き合わせる」である。 issue-startがインストールされておらず、任せる先に到達できないときは、合格として扱わずに完了を止め、入れる手順(gh skill install shoji9x9/skills issue-start)を示す。- 結果を Issue にコメントし、チェックを付ける手順は、
issue-startのreferences/acceptance.mdの手順 7 に従う。自律実行では行わず、保留に積む。
完了報告には、次のものを並べる。
- 受け入れ条件の突き合わせの、行ごとの状態と根拠の強さ(実測か読解か)。
pending-decisionとdeferredの行も省かない。 - 比べなかった操作と遷移(到達できない・承認を得て残した)と、挙げた範囲の外の挙動を引き受ける工程。収束と並べて示す(`references/behavior.md`「完了報告に書くこと」、`references/motion.md`「射程」)。
実行した検証コマンドと結果、反復の回数を、
.replace/components/<slug>/new/<target>/build-metadata.json(環境ごと)に記録する。
commit・push・PR は、issue-startが解決した規約に従う。issue-startの実装の手順には入り直さない。
成果物
すべて対象のプロジェクトの側に置く。スキーマの原本はこのスキルで、テンプレートは `assets/` にある。
ただし、部品インベントリ .replace/components.md の原本は、それを作る replace-strategy である。
| 成果物 | 場所 | 原本のテンプレート |
|---|---|---|
| 要素のスクリーンショット | .replace/components/<slug>/baseline/<instance>/<state>/element.png |
— |
| 撮影の記録(clip・PNG の実寸) | .replace/components/<slug>/baseline/<instance>/<state>/element.shot.json(element-shot.mjs が PNG と対で書く) |
— |
| 計算後スタイル | .replace/components/<slug>/baseline/<instance>/<state>/traits.json |
— |
| 当たっている CSS 規則 | .replace/components/<slug>/baseline/<instance>/<state>/css-rules.json |
— |
| データ依存の部品の実データ | .replace/components/<slug>/baseline/<instance>/data.json |
— |
| 操作の結果(現行) | .replace/components/<slug>/baseline/<instance>/behaviors.json |
`assets/behaviors-template.json` |
| 操作の結果の突き合わせ(環境ごと) | .replace/components/<slug>/new/<target>/behavior-comparison.json |
`assets/behavior-comparison-template.json` |
| 動きの時系列(現行) | .replace/components/<slug>/baseline/<instance>/motions.json |
`assets/motions-template.json` |
| 動きの突き合わせ(環境ごと) | .replace/components/<slug>/new/<target>/motion-comparison.json |
`assets/motion-comparison-template.json` |
| 引数の設計(固定と可変の割り出し) | .replace/components/<slug>/component-api.md |
`assets/component-api-template.md` |
| メタデータとノイズ基準値 | .replace/components/<slug>/metadata.json |
`assets/metadata-template.json` |
| 照合と往復の記録 | .replace/components/<slug>/parity.md |
`assets/parity-template.md` |
| 完了の証跡(環境ごと) | .replace/components/<slug>/new/<target>/build-metadata.json |
`assets/build-metadata-template.json` |
| 受け入れ条件の突き合わせ表(環境ごと) | .replace/components/<slug>/new/<target>/acceptance.json |
様式と検査の原本は、issue-start の assets/acceptance-template.json と scripts/acceptance-check.mjs |
| 未検証の領域 | .replace/components/<slug>/gaps.md |
様式の原本は、parity-suite の assets/gaps-template.md |
| 依存の決定の記録 | .replace/dependencies.md に追記する(既存の行は消さない。無ければテンプレートから作る) |
様式の原本は、replace-strategy の assets/dependencies-template.md |
| 静的資産の台帳への追記 | .replace/assets.md に、台帳に無い資産を方針を空けて追記し(既存の行は消さない)、ユーザーが決めた方針を記録する(無ければテンプレートから作る) |
様式の原本は、replace-strategy の assets/assets-template.md |
| 実装と見本 | 新側のリポジトリ(references.architecture の構成に従う) |
— |
- テキストの成果物は Git で管理する。対象は、特性の JSON・CSS 規則の JSON・操作の結果の JSON・動きの時系列の JSON・
metadata.json・component-api.md・parity.md・gaps.md・new/<target>/acceptance.jsonである。
スクリーンショットなどの大きなバイナリはartifactsの設定に従い、デフォルトはlocal(commit しない)である。 - ノイズを測るための 2 回目の採取物は、成果物ではない。基準値を
metadata.json.noise_baselineに記録したら削除する(原本はparity-suiteのreferences/baseline.md)。 - 差分ツールと特性採取ツールは、
parity-suite同梱のものを原本として使い、このスキルで実装し直さない。実行するときは<parity_suite_dir>/parity/lib/tools/vendor/にコピーし、実際のパスをmetadata.jsonに記録する。
このスキルは機能単位のparity-suiteより先に実行されるので、コピーが無いのが普通である。
インストール済みのparity-suiteから用意する方法と、既存のコピーが同梱版と違うときに停止する取り決めは、`references/capture.md`「parity-suite同梱ツールの用意」にある。 - 次のスクリプトはコピーせず、スキルの中のものをそのまま実行する。
gh skill updateで自動で更新されるようにするためである。 - `scripts/motion-probe.mjs` だけはコピーする。Playwright のスペックから import するためである。
parity-suite同梱のツールと同じ置き場所に、同じ一致の確認をして用意する(`references/motion.md`「時系列を採る」)。
姉妹スキルとの連携
- 依存の順番: 全体の順番の原本は、
replace-strategyのSKILL.md「姉妹スキルと依存順」である(ここへ転記しない)。
このスキル(capture→build)の直前はgolden-dataset(フェーズ A。部品インベントリはreplace-strategy setupの手順 10 が作る)で、直後は各機能のparity-suiteである。
部品を画面より先に作らない方針のプロジェクトでは、このスキルを使わない(機能ごとにparity-replaceが部品も作る)。 replace-strategyから受け取るもの:.replace/components.md(部品・slug・インスタンス・採否・データ依存の有無・Issue 番号)。
このスキルはこのファイルを書かない。Issue 番号を書き戻すのはreplace-strategy issuesである。parity-suiteから受け取るもの: 特性採取ツールと差分ツール、撮影条件とノイズ基準値の規約、状態網羅の導出源の考え方。
対象の slug でparity-suiteを実行しておくことは前提にしない。部品の採取に、ページ単位のスイートは要らない。parity-suiteへ渡すものは無い。ただし、機能の採取が始まったら、部品の基準は、そのインスタンスの現行側のベースラインと同じ現行アプリを指している。
データセットの版が上がったときに部品の基準が古くなるかは、版の数値だけでは決まらない。
記録した版から今までのchanges[].affectsが、その部品の実効参照テーブルと交差するときだけ、古くなったと判定する(原本はgolden-datasetのreferences/versioning.md)。
部品の slug の実効参照テーブルは、インスタンスのページ →features.mdのページ一覧 → 機能の slug → テーブルの順にたどり、和集合をとって求める。parity-replaceとの関係: 機能の実装中に共通部品を変える必要が出たときの取り決めは、`references/amend.md` で定義し、parity-replaceはそこに任せる。
逆に、敵対的レビューとテーマ寄せの手順はparity-replaceの references が原本で、このスキルがそこに任せる。parity-diffとの関係: このスキルの照合の対象は、カタログ上の部品単体である。画面に載せた後の差分はparity-diffが見る。
部品が単体で合っていても、画面では合わないことがある(周りの余白・親の指定の継承)。このスキルの収束を、機能の収束の代わりにしない。