establishing-code-ownership について
分散した `owners.yaml` を `hogli owners:*` で解析し、PostHog のコード所有者を特定する開発スキルです。手作業でファイルを解釈せずに済むよう、解決ルールと代替情報源を説明します。
主な機能
- 01単一パスまたは複数パスの所有者解決
- 02所有者未設定の追跡ファイルの一覧表示
- 03継承と最寄りファイル優先の説明
- 04コード所有者と CODEOWNERS 承認の区別
- 05生成ファイルの入力元の追跡
活用シーン
- 01パスの所有者と Slack チャンネルの確認
- 02リポジトリ内の所有者不在ファイルの監査
- 03コード領域を担当するチームの特定
- 04生成物の実質的なソース所有者の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ posthog --skill establishing-code-ownershipインストール後、Claude Code で/establishing-code-ownershipを入力して読み込まれたか確認します。
詳細
コードオーナーシップの確認
オーナーシップは、分散した owners.yaml ファイルを対象に、1 つのツールである hogli owners:* によって解決されます。
オーナーシップファイルを手作業で再解析しないでください。意味を解釈するのはリゾルバーであり、CI が適用するのもリゾルバーです。
まずはこれだけ:hogli owners:*
開発マシンには flox/hogli があるため、シェルから直接リゾルバーを実行できます。
hogli owners:who posthog/hogql/printer.py # who owns this path (+ the file that decided it)
hogli owners:resolve --json posthog/api/survey.py products/surveys/backend/api.py # batch, JSON keyed by path
hogli owners:unowned # every tracked file with no owner (append a prefix to scope: `owners:unowned products/`)
owners:who は、解決された owners、status、Slack チャンネル、そして結果を決定した owners.yaml/product.yaml ファイルである source を表示します。
チャンネルは、プライマリオーナーのルート teams: レジストリーエントリーから取得されます。それがなければ #<slug> が生成されます。プライマリオーナーが @handle のパスにはチャンネルがありません。
owners:resolve は、引数としてパスを受け取ることも、標準入力から改行区切りで受け取ることもできるため、ファイル一覧をパイプで渡せます:git ls-files posthog/hogql | hogli owners:resolve --json。
hogli/flox が利用できない場合、依存関係を最小限に抑えた代替手段には pyyaml だけが必要です:git ls-files posthog/hogql | PYTHONPATH=packages/owners-yaml python -m owners_yaml(標準入力のパス → 同じ JSON)。
解決アルゴリズム(リゾルバーの処理内容)
パスに対して、リポジトリのルートからそのパスまでたどってオーナーシップファイルを収集し、最も近いファイルを優先してマージします:
owners.yaml— 正式な分散ソースです。 各ディレクトリに 1 つ置けます。フィールド(owners、status、inherit、パスごとのrules)は、上書きされない限り最も近い祖先から引き継がれます。inherit: falseは探索を打ち切ります(Gerrit のset noparentと同じです)。それより上位の設定は何も適用されません。ファイル内では、条件に一致するルールがすべて順に適用され、それぞれが設定するフィールドだけを置き換えます。owners: nullは意図的にオーナーなし(カバレッジチェックの対象外)を意味し、ファイルがないディレクトリが(実際に)オーナーなしである状態とは異なります。additions:はディレクトリ以下で追加されたもののオーナーを指定します。そのディレクトリ内のファイルのオーナーではありません(何を追加とみなすかは利用側が決定します)。ownersは変更せず、探索全体を通じて加算されるため、入れ子のファイルが祖先のエントリーを削除することはできません。sensitive: trueは、小さな変更でも重要なパス(CI のベースラインや除外リストなど)を示します。そのため、変更の規模にかかわらず、レビュアー割り当て処理は該当するオーナーにレビューを依頼します。これはstatusと同様、最も近い設定が優先されます。product.yamlでも設定できますが、レビューを必須にするものではありません。products/<name>/product.yaml— 認められている別名です。 ルートのowners.yamlでalias_files: [product.yaml]を設定すると有効になります。プロダクトのディレクトリにowners.yamlがない場合、product.yamlのowners:リストがproducts/<name>/**のオーナーシップとして読み込まれ、そのツリーにはsensitive:フラグも適用されます(それ以外のproduct.yamlフィールドはすべて無視されます)。両方のファイルがあるディレクトリは lint エラーとなり、owners.yamlが優先されます。.github/CODEOWNERS— 承認をブロックしますが、探索には含まれません。 GitHub ネイティブのセマンティクスを維持し、主にインフラ(例:team-security)について手動で管理され、GitHub 自体によって適用されます。リゾルバーはこれを読み込みません。ブロック対象の承認が追加で必要かどうかを確認するには、ファイルを直接参照してください。解決されたownersがこれによって変更されることはなく、ここにある仕組みがこのファイルに書き込むこともありません。 CODEOWNERS しか読み取れないツールには、代わりにhogli owners:codeownersから生成されたマップの投影が提供されます(packages/owners-yaml/README.md を参照)。この投影にはテストファイルも含まれ、.github/CODEOWNERSにはなりません。
オーナーは、チームスラッグ(team-devex、conversations、logs — @PostHog/ を除いた GitHub チームハンドル)と、個人の @handles を混在させたリストです。最初のエントリーがプライマリオーナーです。
チーム → コード(このチームの担当範囲は?)
「チーム → ファイル」を一括で確認するコマンドはありません。ツリーを解決して、スラッグで絞り込みます:
git ls-files | hogli owners:resolve --json | jq -r 'to_entries[] | select(.value.owners | index("team-surveys")) | .key'
また、products/*/product.yaml でスラッグを検索してください。一致する各ファイルは、その products/<name>/** 全体を示します。同じチームが複数を担当することも多いため、最初の一致だけで終わらせないでください。
担当パスはバックエンドと frontend/src/... の両方にまたがります。両方を確認するか、片方だけを対象とする場合は最初にそう明記してください。
生成されたファイル
生成された成果物は、多くの場合、広範な親オーナーまたは誰にも解決されません。
それが生成元の入力までたどり、そのチームを論理的なオーナーとして報告します(例: services/mcp/src/tools/generated/<x>.ts は products/<name>/mcp/tools.yaml から生成されます)。
論理的なオーナー(ソースを所有するチーム — 報告すべき答え)と、生成されたパス上でのリテラルなリゾルバーの結果を区別し、そのギャップをフラグとして示して、オペレーターが rules: エントリで固定すべきかどうかを判断できるようにします。
最後の手段: 機能オーナーシップハンドブック、次に Slack
リゾルバーでも product.yaml でも解決できない場合は、機能オーナーシップハンドブックを参照してください — これは粗い粒度(ファイル単位ではなく広範な領域)で手動で維持されているため、リポジトリのファイルを優先し、ハンドブックから得た回答には古くなっている可能性があるとフラグを立ててください。
それでも解決できず、Slack MCP が利用可能な場合は、Slack を検索してください — 最も信頼性が低い(意見や古いスレッド)ため、リポジトリのファイルと照合して検証し、Slack から得た回答であるとフラグを立ててください。
スラッグとハンドル
- ハンドル(
CODEOWNERS):@PostHog/<slug>、例:@PostHog/team-replay。 - スラッグ(
owners.yaml/product.yaml): ハンドルから@PostHog/を除いたもの、例:team-replay。 - 均一ではない: 一部は
team-が付き(team-self-driving)、一部は付きません(conversations、logs)。名前が解決できない場合は、両方の形式を試してください。